Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions __mocks__/cosmiconfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { vol } from 'memfs'

const loadConfigFile = filePath => {
const fileContent: string = vol.readFileSync(filePath, 'utf8') as string
const config = JSON.parse(fileContent)
return { config }
}

const explorer = { loadSync: loadConfigFile }

const cosmiconfig = jest.fn(() => explorer)

module.exports = cosmiconfig
11 changes: 11 additions & 0 deletions __mocks__/fs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { vol } from 'memfs'

const fs = jest.requireActual('fs')

function mockedWriteFile(path: string, content: string) {
vol.writeFileSync(path, content)
}

jest.spyOn(fs, 'writeFile').mockImplementation(mockedWriteFile)

module.exports = fs
13 changes: 13 additions & 0 deletions __mocks__/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const util = jest.requireActual('util')

function promisify(fn) {
return (...args) => {
return new Promise(resolve => {
resolve(fn(...args))
})
}
}

util.promisify = promisify

module.exports = util
13 changes: 10 additions & 3 deletions dist/commands/generate.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,25 @@ const tslib_1 = require('tslib')
const command_1 = require('@oclif/command')
const fs = require('fs')
const html_ui_prototyper_1 = require('../html-ui-prototyper')
const printer_1 = require('../utils/printer')
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 printer = new printer_1.default()
try {
const { flags } = this.parse(Generate)
if (!flags.features) throw new Error('Missing flag --features')
const processResult = JSON.parse(flags.features)
if (processResult.features.length === 0)
throw new Error('No features found')
const generator = new html_ui_prototyper_1.default(
fs,
flags.outputDir
)
const result = yield generator.generate(processResult.features)
this.log(JSON.stringify(result))
printer.printGeneratedFiles(result)
} catch (e) {
printer.printErrorMessage(e.message)
}
})
}
Expand Down
12 changes: 7 additions & 5 deletions dist/html-ui-prototyper.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ const tslib_1 = require('tslib')
const fs = require('fs')
const util_1 = require('util')
const path_1 = require('path')
const prettier = require('prettier')
const case_converter_1 = require('./utils/case-converter')
const format_html_1 = require('./utils/format-html')
const cosmiconfig = require('cosmiconfig')
const { normalize } = require('normalize-diacritics')
const widget_factory_1 = require('./widgets/widget-factory')
class HtmlUIPrototyper {
constructor(_fs = fs, _outputDir) {
Expand All @@ -30,13 +32,13 @@ class HtmlUIPrototyper {
}
createHtmlFile(fileName, widgets) {
return tslib_1.__awaiter(this, void 0, void 0, function*() {
fileName = yield normalize(
case_converter_1.convertCase(fileName, 'snake')
)
let content = widgets.reduce((result, widget) => {
return result + widget.renderToString()
}, '')
content = prettier.format(`<form>\n${content}</form>`, {
parser: 'html',
htmlWhitespaceSensitivity: 'ignore',
})
content = format_html_1.formatHtml(`<form>${content}</form>`)
const path = path_1.format({
dir: this._outputDir,
name: fileName,
Expand Down
24 changes: 19 additions & 5 deletions dist/interfaces/app-config.d.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
export interface AppConfig {
widgets?: {
input?: WidgetConfig;
[key: string]: WidgetConfig;
};
}
export interface WidgetConfig {
opening: string;
closure?: string;
wrapperOpening?: string;
wrapperClosure?: string;
template?: string;
widget: {
opening: string;
closure?: string;
onePerValue?: boolean;
};
valueWrapper?: {
opening: string;
closure: string;
};
wrapper?: {
opening: string;
closure: string;
};
label?: {
opening: string;
closure: string;
};
}
1 change: 1 addition & 0 deletions dist/utils/case-converter.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare function convertCase(text: string, type: string): string;
30 changes: 30 additions & 0 deletions dist/utils/case-converter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use strict'
Object.defineProperty(exports, '__esModule', { value: true })
const case_1 = require('case')
var CaseType
;(function(CaseType) {
CaseType['CAMEL'] = 'camel'
CaseType['PASCAL'] = 'pascal'
CaseType['SNAKE'] = 'snake'
CaseType['KEBAB'] = 'kebab'
})(CaseType || (CaseType = {}))
function convertCase(text, type) {
switch (
type
.toString()
.trim()
.toLowerCase()
) {
case CaseType.CAMEL:
return case_1.camel(text)
case CaseType.PASCAL:
return case_1.pascal(text)
case CaseType.SNAKE:
return case_1.snake(text)
case CaseType.KEBAB:
return case_1.kebab(text)
default:
return text // do nothing
}
}
exports.convertCase = convertCase
1 change: 1 addition & 0 deletions dist/utils/format-html.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare function formatHtml(html: string): any;
10 changes: 10 additions & 0 deletions dist/utils/format-html.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'use strict'
Object.defineProperty(exports, '__esModule', { value: true })
const prettier = require('prettier')
function formatHtml(html) {
return prettier.format(html, {
parser: 'html',
htmlWhitespaceSensitivity: 'ignore',
})
}
exports.formatHtml = formatHtml
3 changes: 3 additions & 0 deletions dist/utils/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './case-converter';
export * from './format-html';
export * from './prop';
6 changes: 6 additions & 0 deletions dist/utils/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
'use strict'
Object.defineProperty(exports, '__esModule', { value: true })
const tslib_1 = require('tslib')
tslib_1.__exportStar(require('./case-converter'), exports)
tslib_1.__exportStar(require('./format-html'), exports)
tslib_1.__exportStar(require('./prop'), exports)
4 changes: 4 additions & 0 deletions dist/utils/printer.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export default class Printer {
printGeneratedFiles(files: string[]): void;
printErrorMessage(message: string): void;
}
21 changes: 21 additions & 0 deletions dist/utils/printer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
'use strict'
Object.defineProperty(exports, '__esModule', { value: true })
const Table = require('cli-table3')
const colors = require('colors')
/* tslint:disable:no-console */
class Printer {
printGeneratedFiles(files) {
const table = new Table({
head: [colors.green('#'), colors.green('Generated files')],
})
for (let i = 0; i < files.length; i++) {
const counter = i + 1
table.push([counter, files[i]])
}
console.log(table.toString())
}
printErrorMessage(message) {
console.log(colors.red(message))
}
}
exports.default = Printer
2 changes: 1 addition & 1 deletion dist/utils/prop.d.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export declare function formatProperties(props: any, validProperties: string[]): string;
export declare function formatProperties(props: any, caseType?: string): string;
35 changes: 9 additions & 26 deletions dist/utils/prop.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict'
Object.defineProperty(exports, '__esModule', { value: true })
function formatProperties(props, validProperties) {
const case_converter_1 = require('./case-converter')
function formatProperties(props, caseType = 'camel') {
const translateProp = key => {
switch (key) {
case 'format':
Expand All @@ -9,33 +10,15 @@ function formatProperties(props, validProperties) {
return key
}
}
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}"`
}
}
return `${translateProp(key)}="${value}"`
}
const formatValid = (result, prop) => {
return validProperties.includes(prop)
? result + getFormattedProp(prop) + ' '
: result
const getValueOf = key =>
case_converter_1.convertCase(props[key].toString(), caseType)
const format = (result, key) => {
const value = getValueOf(key)
const htmlProp = translateProp(key)
return result + `${htmlProp}="${value}"` + ' '
}
return Object.keys(props)
.reduce(formatValid, '')
.reduce(format, '')
.trimRight()
}
exports.formatProperties = formatProperties
10 changes: 5 additions & 5 deletions dist/widgets/button.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Widget } from 'concordialang-ui-core';
export default class Button extends Widget {
private readonly VALID_PROPERTIES;
constructor(props: any, name?: string);
renderToString(): string;
import { WidgetConfig } from '../interfaces/app-config';
import HtmlWidget from './html-widget';
export default class Button extends HtmlWidget {
constructor(props: any, name: string, config: WidgetConfig);
protected getFormattedProps(props: any): string;
private getType;
}
28 changes: 14 additions & 14 deletions dist/widgets/button.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
'use strict'
Object.defineProperty(exports, '__esModule', { value: true })
const concordialang_ui_core_1 = require('concordialang-ui-core')
const lodash_1 = require('lodash')
const prop_1 = require('../utils/prop')
class Button extends concordialang_ui_core_1.Widget {
constructor(props, name) {
super(props, name || '')
this.VALID_PROPERTIES = ['id', 'disabled', 'value']
const html_widget_1 = require('./html-widget')
class Button extends html_widget_1.default {
constructor(props, name, config) {
super(props, name, config)
this.props.value = this.props.value || name
}
renderToString() {
// const inputType = this.getType(this.props.datatype as string)
const properties = prop_1.formatProperties(
this.props,
this.VALID_PROPERTIES
)
// return `<button ${inputType}${properties}>${this.name}</button>`
return `<button ${properties}>${this.name}</button>`
getFormattedProps(props) {
// Defines the properties that will be injected in the widget and its order.
const VALID_PROPERTIES = ['id', 'type', 'disabled']
props.type = this.getType(props.datatype)
props.value = props.value || this.name
const filteredProps = lodash_1.pick(props, VALID_PROPERTIES)
return prop_1.formatProperties(filteredProps)
}
getType(datatype) {
return `type="${datatype || 'button'}"`
return datatype || 'button'
}
}
exports.default = Button
10 changes: 5 additions & 5 deletions dist/widgets/checkbox.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Widget } from 'concordialang-ui-core';
export default class Checkbox extends Widget {
private readonly VALID_PROPERTIES;
constructor(props: any, name: string);
renderToString(): string;
import { WidgetConfig } from '../interfaces/app-config';
import HtmlWidget from './html-widget';
export default class Checkbox extends HtmlWidget {
constructor(props: any, name: string, config: WidgetConfig);
protected getFormattedProps(props: any): string;
}
28 changes: 12 additions & 16 deletions dist/widgets/checkbox.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
'use strict'
Object.defineProperty(exports, '__esModule', { value: true })
const concordialang_ui_core_1 = require('concordialang-ui-core')
const lodash_1 = require('lodash')
const prop_1 = require('../utils/prop')
class Checkbox extends concordialang_ui_core_1.Widget {
constructor(props, name) {
super(props, name)
this.VALID_PROPERTIES = ['value', 'required']
const html_widget_1 = require('./html-widget')
class Checkbox extends html_widget_1.default {
constructor(props, name, config) {
super(props, name, config)
}
// TODO: remove \n
renderToString() {
const properties = prop_1.formatProperties(
this.props,
this.VALID_PROPERTIES
)
if (properties)
return `<div>\n<input type="checkbox" ${properties}>${
this.name
}\n</div>`
return `<div>\n<input type="checkbox">${this.name}\n</div>`
getFormattedProps(props) {
// Defines the properties that will be injected in the widget and its order.
const VALID_PROPERTIES = ['type', 'name', 'value', 'required']
props.type = 'checkbox'
props.name = props.value
const filteredProps = lodash_1.pick(props, VALID_PROPERTIES)
return prop_1.formatProperties(filteredProps)
}
}
exports.default = Checkbox
11 changes: 11 additions & 0 deletions dist/widgets/html-widget.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Widget } from 'concordialang-ui-core';
import { WidgetConfig } from '../interfaces/app-config';
export default abstract class HtmlWidget extends Widget {
private _config;
constructor(props: any, name: string, _config: WidgetConfig);
renderToString(): string;
protected abstract getFormattedProps(props: any): string;
private renderWidgetWithSingleValue;
private renderOneWidgetPerValue;
private renderWidgetWithMultipleValues;
}
Loading