diff --git a/assets/templates/component-container.template b/assets/templates/component-container.template index 8b9b014..07e4e01 100644 --- a/assets/templates/component-container.template +++ b/assets/templates/component-container.template @@ -18,12 +18,31 @@ class {componentName} extends PureComponent { componentDidMount = () => { console.log('{componentName} mounted'); } - + componentWillReceiveProps = (nextProps) => { console.log('{componentName} will receive props', nextProps); } - - componentWillUnMount = () => { + + + getDerivedStateFromProps = (nextProps, prevState) => { + console.log('{componentName} getDerivedStateFromProps', nextProps, prevState); + } + + + componentWillUpdate = (nextProps, nextState) => { + console.log('{componentName} will update', nextProps, nextState); + } + + + getSnapshotBeforeUpdate = (prevProps, prevState) => { + console.log('{componentName} getSnapshotBeforeUpdate', prevProps, prevState); + } + + componentDidUpdate = () => { + console.log('{componentName} did update'); + } + + componentWillUnmount = () => { console.log('{componentName} will unmount'); } diff --git a/assets/templates/component-reduxContainer.template b/assets/templates/component-reduxContainer.template index abd83e4..2b98153 100644 --- a/assets/templates/component-reduxContainer.template +++ b/assets/templates/component-reduxContainer.template @@ -19,12 +19,31 @@ class {componentName} extends PureComponent { componentDidMount = () => { console.log('{componentName} mounted'); } - + componentWillReceiveProps = (nextProps) => { console.log('{componentName} will receive props', nextProps); } - - componentWillUnMount = () => { + + + getDerivedStateFromProps = (nextProps, prevState) => { + console.log('{componentName} getDerivedStateFromProps', nextProps, prevState); + } + + + componentWillUpdate = (nextProps, nextState) => { + console.log('{componentName} will update', nextProps, nextState); + } + + + getSnapshotBeforeUpdate = (prevProps, prevState) => { + console.log('{componentName} getSnapshotBeforeUpdate', prevProps, prevState); + } + + componentDidUpdate = () => { + console.log('{componentName} did update'); + } + + componentWillUnmount = () => { console.log('{componentName} will unmount'); } diff --git a/config/config.json b/config/config.json deleted file mode 100644 index e9cfcb0..0000000 --- a/config/config.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "global": { - "quotes": "single", - "generateFolder": true - }, - "files": { - "component": { - "create": true, - "extension": "jsx" - }, - "style": { - "create": true, - "type": "styled", - "suffix": ".styles", - "extension": "js" - }, - "index": { - "create": true, - "extension": "js" - } - } -} \ No newline at end of file diff --git a/package.json b/package.json index 4da0a70..471f3bc 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,8 @@ "vscode": "^1.29.0" }, "categories": [ + "Programming Languages", + "Snippets", "Other" ], "keywords": [ @@ -50,9 +52,71 @@ "type": "object", "title": "AC React Component Generator", "properties": { - "AC.ReactComponentGenerator.config": { - "type": "object", - "description": "vscode-react-component-generator configuration object. See: https://github.com/abdullahceylan/vscode-react-component-generator/blob/master/README.md for more information." + "ACReactComponentGenerator.global.quotes": { + "type": "string", + "enum": [ + "single", + "double" + ], + "default": "single", + "description": "Options: `single` or `double` Result: `'` or `\"`" + }, + "ACReactComponentGenerator.global.generateFolder": { + "type": "boolean", + "default": true, + "description": "Generate or not separate folder for newly created component" + }, + "ACReactComponentGenerator.global.lifecycleType": { + "type": "string", + "default": "legacy", + "enum": [ + "legacy", + "reactv16" + ], + "description": "The lifecycle type of generated component. `legacy` is contains componentWillReceiveProps, componentWillMount etc." + }, + "ACReactComponentGenerator.mainFile.create": { + "type": "boolean", + "default": true, + "description": "Weather to generate component's main file or not. e.g.: ComponentName.(extension)" + }, + "ACReactComponentGenerator.mainFile.extension": { + "type": "string", + "default": "jsx", + "description": "The extension of generated component file" + }, + "ACReactComponentGenerator.styleFile.create": { + "type": "boolean", + "default": true, + "description": "Weather to generate component's style file or not. e.g.: ComponentName.(extension)" + }, + "ACReactComponentGenerator.styleFile.type": { + "type": "string", + "enum": [ + "styled-components (.js)", + "emotion (.js)", + "standard (.css)", + "sass (.sass)", + "less (.less)" + ], + "default": "styled-components (.js)", + "description": "The type of stylesheet file to create" + }, + + "ACReactComponentGenerator.styleFile.suffix": { + "type": "string", + "default": ".styles", + "description": "The suffix to add to the end of the stylesheet filename. Default: ComponentName.styles.(extension)" + }, + "ACReactComponentGenerator.indexFile.create": { + "type": "boolean", + "default": true, + "description": "Weather to generate component's index file or not. e.g.: index.(extension)" + }, + "ACReactComponentGenerator.indexFile.extension": { + "type": "string", + "default": "js", + "description": "The extension of generated component index file" } } }, diff --git a/src/config.interface.ts b/src/config.interface.ts index bc26d2b..e43f73a 100644 --- a/src/config.interface.ts +++ b/src/config.interface.ts @@ -1,8 +1,6 @@ -import FileConfig from './interfaces/files.interface'; import GlobalConfig from './interfaces/global.interface'; import { WorkspaceConfiguration } from 'vscode'; export interface Config extends WorkspaceConfiguration { global: GlobalConfig, - files: FileConfig }; diff --git a/src/extension.ts b/src/extension.ts index 639f67f..9e1b772 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -4,7 +4,6 @@ import { ExtensionContext, workspace, window, commands } from 'vscode'; import { paramCase } from 'change-case'; import { Observable } from 'rxjs'; -import { assign } from "lodash"; import { FileHelper, logger } from './helpers'; import { Config as ConfigInterface } from './config.interface'; @@ -16,15 +15,6 @@ const TEMPLATE_SUFFIX_SEPERATOR = '-'; export function activate(context: ExtensionContext) { const createComponent = (uri, suffix: string = '') => { - let configPrefix: String = 'AC.ReactComponentGenerator'; - let defaultConfig: ConfigInterface = FileHelper.getDefaultConfig(); - let userConfig: ConfigInterface = workspace.getConfiguration((configPrefix + '.config')); - let config: ConfigInterface; - - if (userConfig) { - config = assign(config, defaultConfig, userConfig) as ConfigInterface; - } - // Display a dialog to the user let enterComponentNameDialog$ = Observable.from( window.showInputBox( @@ -38,12 +28,12 @@ export function activate(context: ExtensionContext) { throw new Error('Component name can not be empty!'); } let componentName = paramCase(val); - let componentDir = FileHelper.createComponentDir(uri, componentName, config.global); + let componentDir = FileHelper.createComponentDir(uri, componentName); return Observable.forkJoin( - FileHelper.createComponent(componentDir, componentName, config.global, config.files, suffix), - FileHelper.createIndexFile(componentDir, componentName, config.global, config.files.index), - FileHelper.createCSS(componentDir, componentName, config.global, config.files.style), + FileHelper.createComponent(componentDir, componentName, suffix), + FileHelper.createIndexFile(componentDir, componentName), + FileHelper.createCSS(componentDir, componentName), ); }) .concatMap(result => Observable.from(result)) diff --git a/src/helpers.ts b/src/helpers.ts index f7a22d6..e7fe4c9 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -1,26 +1,26 @@ -import { workspace, window } from 'vscode'; +import { workspace, Uri, window } from 'vscode'; import * as fse from 'fs-extra'; import * as fs from 'fs'; import * as path from 'path'; import { pascalCase } from 'change-case'; import { Observable } from 'rxjs'; -import FileInterface from './interfaces/files.interface'; +import { + IndexInterface, + CSSInterface, + ComponentInterface, +} from './interfaces/types'; import GlobalInterface from './interfaces/global.interface'; // import { Config as ConfigInterface } from './config.interface'; -import { - IndexInterface, - CSSInterface, -} from './interfaces/types'; export class FileHelper { - private static rootDir: string = path.join(__dirname, '../..'); private static assetRootDir: string = path.join(__dirname, '../../assets'); private static createFile = <(file: string, data: string) => Observable<{}>>Observable.bindNodeCallback(fse.outputFile); - public static createComponentDir(uri: any, componentName: string, globalConfig: GlobalInterface): string { + public static createComponentDir(uri: any, componentName: string): string { let contextMenuSourcePath; + const globalConfig: GlobalInterface = getConfig().get('global'); if (uri && fs.lstatSync(uri.fsPath).isDirectory()) { contextMenuSourcePath = uri.fsPath; @@ -39,22 +39,29 @@ export class FileHelper { return componentDir; } - public static createComponent(componentDir: string, componentName: string, globalConfig: GlobalInterface, config: FileInterface, suffix: string = '-container'): Observable { - + public static createComponent(componentDir: string, componentName: string, suffix: string = '-container'): Observable { + const globalConfig: GlobalInterface = getConfig().get('global'); + const componentConfig: ComponentInterface = getConfig().get('mainFile'); let templateFileName = this.assetRootDir + `/templates/component${suffix}.template`; - if (config.component.template) { - templateFileName = this.resolveWorkspaceRoot(config.component.template); + if (componentConfig.template) { + templateFileName = this.resolveWorkspaceRoot(componentConfig.template); } const compName = this.setName(componentName); + const removeLifecycleType = globalConfig.lifecycleType == 'legacy' ? 'reactv16' : 'legacy'; + console.log('removeLifecycleType', removeLifecycleType); let componentContent = fs.readFileSync( templateFileName ).toString() .replace(/{componentName}/g, compName) - .replace(/{quotes}/g, this.getQuotes(globalConfig)); + .replace(/{quotes}/g, this.getQuotes(globalConfig)) + + // console.log('content', componentContent); - let filename = `${componentDir}/${compName}.${config.component.extension}`; + componentContent = removeBetweenTags(globalConfig.lifecycleType, removeLifecycleType, componentContent); - if (config.component.create) { + let filename = `${componentDir}/${compName}.${componentConfig.extension}`; + + if (componentConfig.create) { return this.createFile(filename, componentContent) .map(result => filename); } @@ -63,10 +70,13 @@ export class FileHelper { } }; - public static createIndexFile(componentDir: string, componentName: string, globalConfig: GlobalInterface, config: IndexInterface): Observable { - let templateFileName = this.assetRootDir + '/templates/index.template'; - if (config.template) { - templateFileName = this.resolveWorkspaceRoot(config.template); + public static createIndexFile(componentDir: string, componentName: string): Observable { + const globalConfig: GlobalInterface = getConfig().get('global'); + const indexConfig: IndexInterface = getConfig().get('indexFile'); + + let templateFileName = this.assetRootDir + '/templates/index.template'; + if (indexConfig.template) { + templateFileName = this.resolveWorkspaceRoot(indexConfig.template); } const compName = this.setName(componentName); @@ -74,8 +84,8 @@ export class FileHelper { .replace(/{componentName}/g, compName) .replace(/{quotes}/g, this.getQuotes(globalConfig)); - let filename = `${componentDir}/index.${config.extension}`; - if (config.create) { + let filename = `${componentDir}/index.${indexConfig.extension}`; + if (indexConfig.create) { return this.createFile(filename, indexContent) .map(result => filename); } @@ -84,38 +94,30 @@ export class FileHelper { } }; - public static createCSS(componentDir: string, componentName: string, globalConfig: GlobalInterface, config: CSSInterface): Observable { - let templateFileName = this.assetRootDir + '/templates/css.template'; - if (config.type === 'emotion') { - templateFileName = this.assetRootDir + '/templates/css-emotion.template'; - } else if (config.type === 'styled') { - templateFileName = this.assetRootDir + '/templates/css-styled.template'; - } - if (config.template) { - templateFileName = this.resolveWorkspaceRoot(config.template); - } - - const compName = this.setName(componentName); - let cssContent = fs.readFileSync( templateFileName ).toString() - .replace(/{componentName}/g, compName) - .replace(/{quotes}/g, this.getQuotes(globalConfig)); - - let filename = `${componentDir}/${compName}${config.suffix}.${config.extension}`; - if (config.create) { - return this.createFile(filename, cssContent) - .map(result => filename); - } - else { - return Observable.of(''); - } + public static createCSS(componentDir: string, componentName: string): Observable { + const globalConfig: GlobalInterface = getConfig().get('global'); + const styleConfig: CSSInterface = getConfig().get('styleFile'); + const styleTemplate = getStyleSheetExtTemplate(); + let templateFileName = `${this.assetRootDir}/templates/${styleTemplate.template}`; + // if (styleConfig.template) { + // templateFileName = this.resolveWorkspaceRoot(styleConfig.template); + // } + + const compName = this.setName(componentName); + let cssContent = fs.readFileSync( templateFileName ).toString() + .replace(/{componentName}/g, compName) + .replace(/{quotes}/g, this.getQuotes(globalConfig)); + + let filename = `${componentDir}/${compName}${styleConfig.suffix}.${styleTemplate.ext}`; + if (styleConfig.create) { + return this.createFile(filename, cssContent) + .map(result => filename); + } + else { + return Observable.of(''); + } }; - public static getDefaultConfig(): any { - let content = fs.readFileSync( this.rootDir + '/config/config.json' ).toString(); - content = content.replace(/\${workspaceFolder}/g, workspace.rootPath); - return JSON.parse(content); - } - public static resolveWorkspaceRoot = (path: string): string => path.replace('${workspaceFolder}', workspace.rootPath) private static getQuotes = (config: GlobalInterface) => config.quotes === "double" ? '"' : '\'' @@ -134,4 +136,47 @@ export function logger(type: 'success'|'warning'|'error', msg: string = '') { case 'error': return window.showErrorMessage(`Failed: ${msg}`); } - } \ No newline at end of file + } + + + +export default function getConfig(uri?: Uri) { + return workspace.getConfiguration('ACReactComponentGenerator', uri) as any; +} + +export function getStyleSheetExtTemplate() { + const configuredView = getConfig().get('styleFile.type'); + let styleTemplate = { + ext: 'css', + template: 'css.template', + }; + + console.log('configuredView', configuredView); + + switch (configuredView) { + case 'styled-components (.js)': + styleTemplate = { ext: 'js', template: 'css-styled.template' }; + break; + case 'emotion (.js)': + styleTemplate = { ext: 'js', template: 'css-emotion.template' }; + break; + case 'sass (.sass)': + styleTemplate.ext = 'sass'; + break; + case 'less (.less)': + styleTemplate.ext = 'less'; + break; + } + + return styleTemplate; +} + +export function removeBetweenTags(remainTag, removedtag, content) { + console.log("​removeBetweenTags -> removedtag", removedtag) + console.log("​removeBetweenTags -> remainTag", remainTag) + const escapeRegExp = s => s.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&"); + const regexPattern = RegExp(`${escapeRegExp(`<${removedtag}>`)}([\\S\\s]+?)${escapeRegExp(``)}`, "gi"); + const removeOnlyTagsPattern = new RegExp(`<(${escapeRegExp(remainTag)}|/${escapeRegExp(remainTag)})[^>]{0,}>`, "gi"); + + return content.replace(regexPattern, '').replace(removeOnlyTagsPattern, ''); +} \ No newline at end of file diff --git a/src/interfaces/files.interface.ts b/src/interfaces/files.interface.ts index 0c8610c..6f6e29d 100644 --- a/src/interfaces/files.interface.ts +++ b/src/interfaces/files.interface.ts @@ -4,8 +4,8 @@ import { ComponentInterface, } from './types'; -export default interface FileInterface { - component: ComponentInterface, - style: CSSInterface, - index: IndexInterface, -} \ No newline at end of file +export { + IndexInterface, + CSSInterface, + ComponentInterface, +}; diff --git a/src/interfaces/global.interface.ts b/src/interfaces/global.interface.ts index b08d82e..d10f441 100644 --- a/src/interfaces/global.interface.ts +++ b/src/interfaces/global.interface.ts @@ -1,4 +1,5 @@ export default interface GlobalInterface { quotes?: string, - generateFolder?: boolean + generateFolder?: boolean, + lifecycleType?: string, } \ No newline at end of file