commit dbdf7d00336bb4b73ec949797c6b948a813bd487 Author: jiangzhixiong <710328466@qq.com> Date: Thu May 16 10:31:01 2024 +0800 feat: 初始化仓库 diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..10b3143 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,282 @@ +const path = require('path'); + +module.exports = { + env: { + es6: true, + browser: true, + node: true, + }, + + parserOptions: { + sourceType: 'module', + ecmaFeatures: { + jsx: true, + }, + }, + + extends: ['eslint-config-prettier'], + + plugins: [ + 'babel', + 'eslint-comments', + 'import', + 'prettier', + 'simple-import-sort', + ], + + rules: { + 'array-callback-return': 'error', + 'babel/no-invalid-this': 'error', + 'babel/valid-typeof': 'error', + 'constructor-super': 'error', + 'default-case': ['error', { commentPattern: '^no default$' }], + 'eslint-comments/disable-enable-pair': ['error', { allowWholeFile: true }], + 'eslint-comments/no-aggregating-enable': 'error', + 'eslint-comments/no-duplicate-disable': 'error', + 'eslint-comments/no-unlimited-disable': 'error', + 'eslint-comments/no-unused-disable': 'error', + 'eslint-comments/no-unused-enable': 'error', + 'for-direction': 'error', + 'getter-return': 'error', + 'import/export': 'error', + 'import/extensions': 'off', + 'import/imports-first': 'error', + 'import/named': 'off', + 'import/no-amd': 'error', + 'import/no-commonjs': 'error', + 'import/no-duplicates': 'error', + 'import/no-extraneous-dependencies': 'error', + 'import/no-self-import': 'error', + 'new-parens': 'error', + 'no-array-constructor': 'error', + 'no-caller': 'error', + 'no-case-declarations': 'error', + 'no-class-assign': 'error', + 'no-compare-neg-zero': 'error', + 'no-cond-assign': ['error', 'except-parens'], + 'no-const-assign': 'error', + 'no-constant-condition': 'error', + 'no-control-regex': 'error', + 'no-delete-var': 'error', + 'no-dupe-args': 'error', + 'no-dupe-class-members': 'error', + 'no-dupe-keys': 'error', + 'no-duplicate-case': 'error', + 'no-empty': 'error', + 'no-empty-character-class': 'error', + 'no-empty-pattern': 'error', + 'no-eval': 'error', + 'no-ex-assign': 'error', + 'no-extend-native': 'error', + 'no-extra-bind': 'error', + 'no-extra-boolean-cast': 'error', + 'no-extra-label': 'error', + 'no-extra-semi': 'error', + 'no-fallthrough': 'error', + 'no-func-assign': 'error', + 'no-global-assign': 'error', + 'no-implied-eval': 'error', + 'no-inner-declarations': 'error', + 'no-invalid-regexp': 'error', + 'no-iterator': 'error', + 'no-label-var': 'error', + 'no-labels': ['error', { allowLoop: true, allowSwitch: false }], + 'no-lone-blocks': 'error', + 'no-loop-func': 'error', + 'no-misleading-character-class': 'error', + 'no-multi-str': 'error', + 'no-new-func': 'error', + 'no-new-object': 'error', + 'no-new-symbol': 'error', + 'no-new-wrappers': 'error', + 'no-obj-calls': 'error', + 'no-octal': 'error', + 'no-octal-escape': 'error', + 'no-redeclare': 'error', + 'no-regex-spaces': 'error', + 'no-self-assign': 'error', + 'no-self-compare': 'error', + 'no-shadow-restricted-names': 'error', + 'no-sparse-arrays': 'error', + 'no-this-before-super': 'error', + 'no-throw-literal': 'error', + 'no-undef': 'error', + 'no-unexpected-multiline': 'error', + 'no-unreachable': 'error', + 'no-unsafe-finally': 'error', + 'no-unsafe-negation': 'error', + 'no-unused-labels': 'error', + 'no-unused-vars': 'error', + 'no-use-before-define': [ + 'error', + { functions: false, classes: false, variables: false }, + ], + 'no-useless-computed-key': 'error', + 'no-useless-concat': 'error', + 'no-useless-constructor': 'error', + 'no-useless-escape': 'error', + 'no-useless-rename': 'error', + 'no-with': 'error', + 'require-yield': 'error', + 'simple-import-sort/exports': 'error', + 'unicode-bom': 'error', + 'use-isnan': 'error', + eqeqeq: ['error', 'smart'], + + 'import/no-unresolved': [ + 'error', + { caseSensitive: false, ignore: ['vscode'] }, + ], + 'prettier/prettier': [ + 'error', + { + bracketSameLine: false, + bracketSpacing: true, + printWidth: 80, + semi: true, + singleQuote: true, + tabWidth: 2, + trailingComma: 'all', + useTabs: false, + endOfLine: 'auto', + }, + ], + 'simple-import-sort/imports': [ + 'error', + { groups: [['^\\u0000'], ['^@?\\w'], ['^~/'], ['^../'], ['^./']] }, + ], + }, + overrides: [ + { + files: ['*.ts', '*.tsx'], + parser: require.resolve('@typescript-eslint/parser'), + plugins: ['@typescript-eslint/eslint-plugin'], + settings: { + 'import/extensions': ['.js', '.ts', '.tsx'], + 'import/parsers': { + '@typescript-eslint/parser': ['.ts', '.tsx'], + }, + 'import/resolver': { + node: { + extensions: ['.js', '.ts', '.tsx'], + }, + }, + }, + rules: { + '@typescript-eslint/adjacent-overload-signatures': 'error', + '@typescript-eslint/array-type': 'error', + '@typescript-eslint/consistent-type-assertions': [ + 'error', + { assertionStyle: 'as' }, + ], + '@typescript-eslint/member-delimiter-style': 'error', + '@typescript-eslint/no-array-constructor': 'error', + '@typescript-eslint/no-dynamic-delete': 'error', + '@typescript-eslint/no-empty-interface': [ + 'error', + { allowSingleExtends: true }, + ], + '@typescript-eslint/no-extra-non-null-assertion': 'error', + '@typescript-eslint/no-extraneous-class': 'error', + '@typescript-eslint/no-misused-new': 'error', + '@typescript-eslint/no-namespace': 'error', + '@typescript-eslint/no-unused-vars': [ + 'error', + { argsIgnorePattern: '^_' }, + ], + '@typescript-eslint/no-use-before-define': [ + 'error', + { + functions: false, + classes: false, + variables: false, + typedefs: false, + }, + ], + '@typescript-eslint/no-useless-constructor': 'error', + '@typescript-eslint/prefer-for-of': 'error', + '@typescript-eslint/prefer-function-type': 'error', + '@typescript-eslint/prefer-namespace-keyword': 'error', + '@typescript-eslint/prefer-optional-chain': 'error', + '@typescript-eslint/triple-slash-reference': 'error', + '@typescript-eslint/unified-signatures': 'error', + 'default-case': 'off', + 'no-dupe-class-members': 'off', + 'no-undef': 'off', + 'no-unused-vars': 'off', + 'no-array-constructor': 'off', + 'no-use-before-define': 'off', + }, + }, + { + plugins: ['jest'], + files: ['*.{spec,test}.{js,ts,tsx}', '**/__tests__/**/*.{js,ts,tsx}'], + env: { + jest: true, + }, + rules: { + 'import/no-extraneous-dependencies': [ + 'error', + { devDependencies: true }, + ], + 'jest/consistent-test-it': ['error', { fn: 'test' }], + 'jest/expect-expect': [ + 'error', + { assertFunctionNames: ['expect', 'element'] }, + ], + 'jest/no-disabled-tests': 'error', + 'jest/no-duplicate-hooks': 'error', + 'jest/no-export': 'error', + 'jest/no-focused-tests': 'error', + 'jest/no-identical-title': 'error', + 'jest/no-jasmine-globals': 'error', + 'jest/no-test-prefixes': 'error', + 'jest/no-test-return-statement': 'error', + 'jest/prefer-todo': 'error', + 'jest/require-to-throw-message': 'error', + 'jest/valid-describe-callback': 'error', + 'jest/valid-expect-in-promise': 'error', + 'jest/valid-expect': 'error', + 'jest/valid-title': 'error', + 'jest/no-restricted-matchers': [ + 'error', + { + toBeTruthy: 'Avoid `toBeTruthy`', + toBeFalsy: 'Avoid `toBeFalsy`', + }, + ], + }, + }, + { + files: ['*.js'], + parser: require.resolve('@babel/eslint-parser'), + parserOptions: { + requireConfigFile: false, + }, + rules: { + 'import/default': 'error', + 'import/namespace': 'error', + 'import/no-named-as-default': 'error', + 'import/no-named-as-default-member': 'error', + 'import/no-cycle': 'error', + 'import/no-deprecated': 'error', + }, + }, + { + files: ['*.config.js', '.*rc.js'], + env: { + node: true, + }, + rules: { + 'import/no-commonjs': 'off', + 'import/no-extraneous-dependencies': [ + 'error', + { devDependencies: true }, + ], + }, + }, + ], + globals: { + jasmine: true, + }, +}; diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..67dfeb3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +*.vsix \ No newline at end of file diff --git a/.vscodeignore b/.vscodeignore new file mode 100644 index 0000000..7fe874a --- /dev/null +++ b/.vscodeignore @@ -0,0 +1,12 @@ +**/*.ts +**/tsconfig.json +node_modules +!file.ts +src +**/tsconfig.json +*.ts +.github/** +.gitignore +.vscode/** +docs/** +src/** diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..14fb9f7 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,13 @@ +# nicecode-snippets + +## 0.2.1 + +### Patch Changes + +- 初始化仓库,发个小版本 + +## 0.2.0 + +### Minor Changes + +- feat: 初始化 diff --git a/README.md b/README.md new file mode 100644 index 0000000..a0ea0d6 --- /dev/null +++ b/README.md @@ -0,0 +1,107 @@ + +## 下载应用 + +> 在 **vscode** 应用商店搜索并下载 **nicecode-react-js-ts-snippets** 即可。 + +## javascript-snippets + +> `imp` => `import xx from xx` + +> `imd` => `import { XX } from 'XX'` + +> `ime` => `import * as XX from 'XX'` + +> `exp` => `export default XX` + +> `clg` => `console.log(XX)` + +> `deas` => `const { XX } = XX` + +## react-snippets + +> `imr` => `import React, {} from 'react'` + +> `useState` => `const [xx, setXX] = useState(XX)` + +> `useEffect` => `useEffect(() => { XX }, [XX])` + +> `useDispatch` => `const dispatch = useDispatch()` + +> `useSelector` => `const XX = useSelector(state => state.XX)` + +...more + +## umi-snippets + +`tsx -> 生成` + +```jsx | pure +import { FC } from 'react' +import { connect, ConnectProps } from 'umi' +import styles from './index.less' + +interface I${1:component} extends ConnectProps { +} + +const $1: FC = (props) => {", + return ( +
${1:component}
+ ) +} + +export default connect(({}: {}) => ({ +}))(${1:component}) +``` + +`mts -> 生成` + +```js | pure +// 2022-08-26 - by dev +import { ImmerReducer, Effect } from 'umi'; +import { SubscriptionsMapObject } from 'dva'; + + +export interface XXModelState { +} + + +export interface XXModelType { + namespace: 'XX'; + state: XXModelState; + effects: { + }; + reducers: { + save: ImmerReducer; + reset: ImmerReducer; + }; + subscriptions: SubscriptionsMapObject; +} + + +const initialState: XXModelState = { +} + + +const XXModel: XXModelType = { + namespace: 'XX', + state: initialState, + effects: { + }, + reducers: { + save(state, { payload }: any) { + return { ...state, ...payload } + }, + reset(state, { payload }: any) { + return { ...initialState } + } + }, + subscriptions: {} +}; + + +export default XXModel; +``` + +## join us + +[Nicecoders Team](https://github.com/nicecoders/nicecode) diff --git a/images/logo.png b/images/logo.png new file mode 100644 index 0000000..3abac1a Binary files /dev/null and b/images/logo.png differ diff --git a/package.json b/package.json new file mode 100644 index 0000000..a75d932 --- /dev/null +++ b/package.json @@ -0,0 +1,128 @@ +{ + "name": "nicecode-snippets", + "displayName": "nicecode-react-js-ts-snippets", + "version": "0.2.1", + "description": "Extensions for React, React-Native and Redux in JS/TS with ES7+ syntax", + "publisher": "devlifestyle", + "icon": "images/logo.png", + "keywords": [ + "snippets", + "flow", + "work", + "nicecode" + ], + "author": "dev <710328466@qq.com>", + "main": "./lib/src/index.js", + "homepage": "https://nicecoders.github.io/nicecode/#/snippets", + "scripts": { + "builder": "vsce package --no-dependencies", + "vscode:prepublish": "yarn compile", + "compile": "rm -rf lib; tsc -p ./ --noEmit false --module commonjs --outDir lib", + "compile:dev": "rm -rf lib; tsc -p ./ --noEmit false --module commonjs --outDir lib", + "lint": "eslint --ext .js,.ts,.tsx ./src/", + "watch": "tsc -watch -p ./", + "typescript": "tsc --noEmit" + }, + "engines": { + "vscode": "^1.64.0" + }, + "license": "MIT", + "categories": [ + "Snippets" + ], + "contributes": { + "commands": [ + { + "command": "nicecodeSnippets.search", + "title": "nicecode search" + } + ], + "keybindings": [ + { + "command": "nicecodeSnippets.search", + "key": "ctrl+alt+r", + "mac": "shift+cmd+r", + "when": "editorTextFocus" + } + ], + "configuration": { + "title": "ES React/React-Native/Redux snippets", + "properties": { + "nicecodeSnippets.settings.prettierEnabled": { + "type": "boolean", + "markdownDescription": "[EXPERIMENTAL: MIGHT NOT WORK]: Integrate prettier settings with code generated from snippets.", + "default": false + }, + "nicecodeSnippets.settings.languageScopes": { + "type": "string", + "markdownDescription": "defines the language scopes for which the snippets will be available.\nUse comma separated values.\nFor example: `typescript,typescriptreact,javascript,javascriptreact`", + "default": "typescript,typescriptreact,javascript,javascriptreact" + } + } + }, + "snippets": [ + { + "language": "javascript", + "path": "./snippets/snippets.json" + }, + { + "language": "javascriptreact", + "path": "./snippets/snippets.json" + }, + { + "language": "typescript", + "path": "./snippets/snippets.json" + }, + { + "language": "typescriptreact", + "path": "./snippets/snippets.json" + } + ] + }, + "repository": { + "type": "git", + "url": "git+https://github.com/nicecoders/nicecoders.github.io.git" + }, + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org" + }, + "bugs": { + "url": "https://github.com/nicecoders/nicecoders.github.io/issues" + }, + "dependencies": { + "prettier": "2.5.1" + }, + "devDependencies": { + "@babel/cli": "7.17.0", + "@babel/eslint-parser": "7.17.0", + "@babel/preset-typescript": "7.16.7", + "@types/node": "17.0.16", + "@types/prettier": "2.4.3", + "@types/vscode": "^1.60.0", + "@typescript-eslint/eslint-plugin": "5.11.0", + "@typescript-eslint/parser": "5.11.0", + "eslint": "8.8.0", + "eslint-config-prettier": "8.3.0", + "eslint-plugin-babel": "5.3.1", + "eslint-plugin-eslint-comments": "3.2.0", + "eslint-plugin-import": "2.25.4", + "eslint-plugin-jest": "26.1.0", + "eslint-plugin-prettier": "4.0.0", + "eslint-plugin-simple-import-sort": "7.0.0", + "prettier": "2.5.1", + "typescript": "^4.8.3" + }, + "prettier": { + "bracketSameLine": false, + "bracketSpacing": true, + "printWidth": 80, + "semi": true, + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "all", + "useTabs": false, + "endOfLine": "auto" + }, + "gitHead": "143fba48314ad1f175de7fed5b83325215ff7380" +} diff --git a/snippets.json b/snippets.json new file mode 100644 index 0000000..a603bb9 --- /dev/null +++ b/snippets.json @@ -0,0 +1,225 @@ +{ + "import": { + "prefix": "imp", + "body": ["import ${2:moduleName} from '${1:module}'"], + "description": "normal import" + }, + "import module": { + "prefix": "imd", + "body": ["import { $2 } from '${1:module}'"], + "description": "importDestructing" + }, + "import everything": { + "prefix": "ime", + "body": ["import * as ${2:alias} from '${1:module}'"], + "description": "importEverything" + }, + "exportDefault": { + "prefix": "exp", + "body": ["export default $1"], + "description": "export default" + }, + "consoleLog": { + "prefix": "clg", + "body": ["console.log(${1:data})"], + "description": "console log" + }, + "destructuringAssignment": { + "prefix": "deas", + "body": ["const { ${2:prop} } = ${1:object}"], + "description": "destructuring assignment" + }, + + "import React": { + "prefix": "imr", + "body": ["import React, {} from 'react'"], + "description": "import React" + }, + "useState": { + "prefix": "useState", + "body": [ + "const [${1:state}, set${1/(.*)/${1:/capitalize}/}] = useState(${2:initialState})" + ], + "description": "useState" + }, + "useEffect": { + "prefix": "useEffect", + "body": ["useEffect(() => {\n\t${1:effect}\n}, [${2:dep}])"], + "description": "useEffect" + }, + "useContext": { + "prefix": "useContext", + "body": ["const ${1:context} = useContext(${2:ContextValue})"], + "description": "useContext" + }, + "reduxActionCreator": { + "prefix": "rxaction", + "body": ["export const ${1:actionName} = (payload) => ({\n\ttype: ${2:type},\n\tpayload\n})"], + "description": "reduxActionCreator" + }, + "useDispatch": { + "prefix": "useDispatch", + "body": ["const dispatch = useDispatch()"], + "description": "useDispatch" + }, + "useSelector": { + "prefix": "useSelector", + "body": ["const ${1:state} = useSelector(state => state.$1)"], + "description": "useSelector" + }, + "useMount": { + "prefix": "useMount", + "body": ["useMount(() => {\n\t${1:fn}\n})"], + "description": "useMount" + }, + "useUnmount": { + "prefix": "useUnmount", + "body": ["useUnmount(() => {\n\t${1:fn}\n})"], + "description": "useUnmount" + }, + "useSetState": { + "prefix": "useSetState", + "body": [ + "const [state, setState] = useSetState(${1:initialState})" + ], + "description": "useSetState" + }, + "useBoolean": { + "prefix": "useBoolean", + "body": [ + "const [${1}, { toggle, setTrue, setFalse }] = useBoolean(${2)" + ], + "description": "useBoolean" + }, + "useToggle": { + "prefix": "useToggle", + "body": [ + "const [${1}, { toggle, set, setLeft, setRight }] = useToggle(${2}, ${3})" + ], + "description": "useToggle" + }, + "useCookieState": { + "prefix": "useCookieState", + "body": [ + "const [${1}, set${1}] = useCookieState('${3:key}')" + ], + "description": "useCookieState" + }, + "useLocalStorageState": { + "prefix": "useLocalStorageState", + "body": [ + "const [${1}, set${1}] = useLocalStorageState('${3:key}')" + ], + "description": "useLocalStorageState" + }, + "useSessionStorageState": { + "prefix": "useSessionStorageState", + "body": [ + "const [${1}, set${1}] = useSessionStorageState('${3:key}')" + ], + "description": "useSessionStorageState" + }, + "useDebounce": { + "prefix": "useDebounce", + "body": [ + "const ${2:debounceVal} = useDebounce(${1:value}, { wait: 1000 })" + ], + "description": "useDebounce" + }, + "useDebounceFn": { + "prefix": "useDebounceFn", + "body": [ + "const { run, cancel, flush } = useDebounceFn(() => {\n\t${1:fn}\n},, { wait: 1000 })" + ], + "description": "useDebounceFn" + }, + "useThrottle": { + "prefix": "useThrottle", + "body": [ + "const ${2} = useThrottle(${1}, { wait: 1000 })" + ], + "description": "useThrottle" + }, + "useThrottleFn": { + "prefix": "useThrottleFn", + "body": [ + "const { run, cancel, flush } = useThrottleFn(() => {\n\t${1:fn}\n},, { wait: 1000 })" + ], + "description": "useThrottleFn" + }, + "functionComponentWithUmi": { + "prefix": "tsx", + "body": [ + "// $CURRENT_YEAR-$CURRENT_MONTH-$CURRENT_DATE - by dev", + "\n", + "import { FC } from 'react'", + "import { connect, ConnectProps } from 'umi'", + "import styles from './index.less'", + "\n", + "interface I${1:component} extends ConnectProps {", + "}", + "\n", + "const ${1:component}: FC = (props) => {", + " return (", + "
${1:component}
", + " )", + " }", + "\n", + "export default connect(({}: {}) => ({", + "}))(${1:component})" + ], + "description": "umi 函数组件模板" + }, + "umiModel": { + "prefix": "mts", + "body": [ + "// $CURRENT_YEAR-$CURRENT_MONTH-$CURRENT_DATE - by dev", + "import { ImmerReducer, Effect } from 'umi';", + "import { SubscriptionsMapObject } from 'dva';", + "\n", + "export interface ${1:component}ModelState {", + "}", + "\n", + "export interface ${1:component}ModelType {", + " namespace: '${1:component}';", + " state: ${1:component}ModelState;", + " effects: {", + " };", + " reducers: {", + " save: ImmerReducer<${1:component}ModelState>;", + " reset: ImmerReducer<${1:component}ModelState>;", + " };", + " subscriptions: SubscriptionsMapObject;", + "}", + "\n", + "const initialState: ${1:component}ModelState = {", + "}", + "\n", + "const ${1:component}Model: ${1:component}ModelType = {", + " namespace: '${1:component}',", + " state: initialState,", + " effects: {", + " // *demo({ payload }, { call, put }) {", + " // const response = yield call(getCaseForm, payload);", + " // yield put({", + " // type: 'save',", + " // payload: response,", + " // });", + " //},", + " },", + " reducers: {", + " save(state, { payload }: any) {", + " return { ...state, ...payload }", + " },", + " reset(state, { payload }: any) {", + " return { ...initialState }", + " }", + " },", + " subscriptions: {}", + "};", + "\n", + + "export default ${1:component}Model;" + ] + } +} diff --git a/src/helpers/extensionConfig.ts b/src/helpers/extensionConfig.ts new file mode 100644 index 0000000..5301a46 --- /dev/null +++ b/src/helpers/extensionConfig.ts @@ -0,0 +1,16 @@ +import { workspace } from 'vscode'; + +export type ExtensionSettings = { + languageScopes: string; + prettierEnabled: boolean; + importReactOnTop: boolean; + typescript: boolean; + typescriptPropsStatePrefix: 'type' | 'interface'; +}; + +const extensionConfig = () => + workspace.getConfiguration( + 'reactSnippets.settings', + ) as unknown as ExtensionSettings; + +export default extensionConfig; diff --git a/src/helpers/formatters.ts b/src/helpers/formatters.ts new file mode 100644 index 0000000..6188083 --- /dev/null +++ b/src/helpers/formatters.ts @@ -0,0 +1,22 @@ +import prettier from 'prettier'; + +import extensionConfig from './extensionConfig'; +import getPrettierConfig from './getPrettierConfig'; +import { + replaceSnippetPlaceholders, + revertSnippetPlaceholders, +} from './snippetPlaceholders'; + +export const formatSnippet = (snippetString: string) => { + return extensionConfig().prettierEnabled + ? prettier.format(snippetString, getPrettierConfig()) + : snippetString; +}; + +export const parseSnippet = (body: string | string[]) => { + const snippetBody = typeof body === 'string' ? body : body.join('\n'); + + return replaceSnippetPlaceholders( + formatSnippet(revertSnippetPlaceholders(snippetBody)), + ); +}; diff --git a/src/helpers/generateSnippets.ts b/src/helpers/generateSnippets.ts new file mode 100644 index 0000000..579dbde --- /dev/null +++ b/src/helpers/generateSnippets.ts @@ -0,0 +1,94 @@ +import { writeFile } from 'fs'; + +import componentsSnippets, { + ComponentsSnippet, +} from '../sourceSnippets/components'; +import consoleSnippets, { ConsoleSnippet } from '../sourceSnippets/console'; +import hooksSnippets, { HooksSnippet } from '../sourceSnippets/hooks'; +import importsSnippets, { ImportsSnippet } from '../sourceSnippets/imports'; +import othersSnippets, { OthersSnippet } from '../sourceSnippets/others'; +import propTypesSnippets, { + PropTypesSnippet, +} from '../sourceSnippets/propTypes'; +import reactNativeSnippets, { + ReactNativeSnippet, +} from '../sourceSnippets/reactNative'; +import reduxSnippets, { ReduxSnippet } from '../sourceSnippets/redux'; +import testsSnippets, { TestsSnippet } from '../sourceSnippets/tests'; +import typescriptSnippets, { + TypescriptSnippet, +} from '../sourceSnippets/typescript'; + +import extensionConfig from './extensionConfig'; +import parseSnippetToBody from './parseSnippetToBody'; +import { replaceSnippetPlaceholders } from './snippetPlaceholders'; + +export type SnippetKeys = + | OthersSnippet['key'] + | HooksSnippet['key'] + | ImportsSnippet['key'] + | ReactNativeSnippet['key'] + | TypescriptSnippet['key'] + | ReduxSnippet['key'] + | ComponentsSnippet['key'] + | ConsoleSnippet['key'] + | PropTypesSnippet['key'] + | TestsSnippet['key']; + +export type Snippet = + | OthersSnippet + | HooksSnippet + | ImportsSnippet + | ReactNativeSnippet + | TypescriptSnippet + | ReduxSnippet + | ComponentsSnippet + | ConsoleSnippet + | PropTypesSnippet + | TestsSnippet; + +export type Snippets = { + [key in SnippetKeys]: Snippet; +}; + +const getSnippets = () => { + const { typescript, languageScopes } = extensionConfig(); + + const snippets = [ + ...(typescript ? typescriptSnippets : []), + ...componentsSnippets, + ...consoleSnippets, + ...hooksSnippets, + ...importsSnippets, + ...propTypesSnippets, + ...reactNativeSnippets, + ...reduxSnippets, + ...testsSnippets, + ...othersSnippets, + ].reduce((acc, snippet) => { + acc[snippet.key] = Object.assign(snippet, { + body: parseSnippetToBody(snippet), + scope: languageScopes, + }); + return acc; + }, {} as Snippets); + + return replaceSnippetPlaceholders(JSON.stringify(snippets, null, 2)); +}; + +const generateSnippets = () => + new Promise((resolve) => { + const jsonSnippets = getSnippets(); + writeFile( + __dirname + '/../snippets/generated.json', + jsonSnippets, + (error) => { + if (error) { + console.error(error); + } + return resolve(true); + }, + ); + }); + +export default generateSnippets; diff --git a/src/helpers/getPrettierConfig.ts b/src/helpers/getPrettierConfig.ts new file mode 100644 index 0000000..30fc1bd --- /dev/null +++ b/src/helpers/getPrettierConfig.ts @@ -0,0 +1,19 @@ +import prettier, { Options } from 'prettier'; + +import extensionConfig from './extensionConfig'; + +let prettierConfig: prettier.Options | null; +prettier + .resolveConfig('', { editorconfig: true }) + .then((config) => (prettierConfig = config)); + +const getPrettierConfig = (): Options => { + const { prettierEnabled } = extensionConfig(); + + return { + parser: 'typescript', + ...(prettierEnabled && prettierConfig), + }; +}; + +export default getPrettierConfig; diff --git a/src/helpers/parseSnippetToBody.ts b/src/helpers/parseSnippetToBody.ts new file mode 100644 index 0000000..b8a7e7e --- /dev/null +++ b/src/helpers/parseSnippetToBody.ts @@ -0,0 +1,23 @@ +import extensionConfig from './extensionConfig'; +import { formatSnippet } from './formatters'; +import { Snippet } from './generateSnippets'; +import replaceOrRemoveReactImport from './replaceOrRemoveReactImport'; + +const parseSnippetToBody = (snippet: Snippet) => { + const { importReactOnTop } = extensionConfig(); + const body = + typeof snippet.body === 'string' ? snippet.body : snippet.body.join('\n'); + + const snippetBody = importReactOnTop + ? body + : replaceOrRemoveReactImport({ + prefix: snippet.prefix, + body: snippet.body, + }); + + const formattedSnippet = formatSnippet(snippetBody).split('\n'); + + return formattedSnippet; +}; + +export default parseSnippetToBody; diff --git a/src/helpers/replaceOrRemoveReactImport.ts b/src/helpers/replaceOrRemoveReactImport.ts new file mode 100644 index 0000000..74d4e51 --- /dev/null +++ b/src/helpers/replaceOrRemoveReactImport.ts @@ -0,0 +1,64 @@ +import { Snippet } from './generateSnippets'; + +const snippetWithReactImportPrefixes = [ + 'rfce', + 'rfc', + 'rfcp', + 'rafce', + 'rafc', + 'rafcp', + 'rnfe', + 'rnfes', + 'rnf', + 'rnfs', + 'stest', + 'sntest', + 'srtest', + 'snrtest', + 'hocredux', + 'hoc', + 'tsrafc', + 'tsrafce', + 'tsrcc', + 'tsrcredux', + 'tsrce', + 'tsrpce', + 'tsrpc', + 'tsrfc', + 'tsrfce', + 'tsrnf', + 'tsrnfs', +]; + +const replaceOrRemoveReactImport = ({ + body, + prefix, +}: { + body: string[]; + prefix: Snippet['prefix']; +}) => { + if (!snippetWithReactImportPrefixes.includes(prefix)) { + return body.join('\n'); + } + + let bodyCopy = [...body]; + const reactImportIndex = bodyCopy.findIndex((line) => + line.match(new RegExp(/import React/, 'g')), + ); + + if (reactImportIndex !== -1) { + const line = bodyCopy[reactImportIndex]; + const newLine = line + .replace(new RegExp(/^import React .*$/, 'g'), '') + .replace(new RegExp(/^import React, /, 'g'), 'import '); + + bodyCopy[reactImportIndex] = newLine; + if (!newLine.length) { + bodyCopy = bodyCopy.filter(Boolean); + } + } + + return bodyCopy.join('\n'); +}; + +export default replaceOrRemoveReactImport; diff --git a/src/helpers/snippetPlaceholders.ts b/src/helpers/snippetPlaceholders.ts new file mode 100644 index 0000000..5896a82 --- /dev/null +++ b/src/helpers/snippetPlaceholders.ts @@ -0,0 +1,43 @@ +import { Mappings, Placeholders } from '../types'; + +import extensionConfig from './extensionConfig'; + +export const replaceSnippetPlaceholders = (snippetString: string) => { + const { typescriptPropsStatePrefix } = extensionConfig(); + const propsPlaceholder = + typescriptPropsStatePrefix === 'type' + ? Mappings.TypeProps + : Mappings.InterfaceProps; + const statePlaceholder = + typescriptPropsStatePrefix === 'type' + ? Mappings.TypeState + : Mappings.InterfaceState; + + return String(snippetString) + .replace(new RegExp(Placeholders.FileName, 'g'), '${1:${TM_FILENAME_BASE}}') + .replace(new RegExp(Placeholders.FirstTab, 'g'), '${1:first}') + .replace(new RegExp(Placeholders.SecondTab, 'g'), '${2:second}') + .replace(new RegExp(Placeholders.ThirdTab, 'g'), '${3:third}') + .replace( + new RegExp(Placeholders.Capitalize, 'g'), + '${1/(.*)/${1:/capitalize}/}', + ) + .replace(new RegExp(Placeholders.TypeProps, 'g'), propsPlaceholder) + .replace(new RegExp(Placeholders.TypeState, 'g'), statePlaceholder); +}; + +export const revertSnippetPlaceholders = (snippetString: string) => { + return String(snippetString) + .replace( + new RegExp(/\${1:\${TM_FILENAME_BASE}}/, 'g'), + Placeholders.FileName, + ) + .replace(new RegExp(/\${1:first}/, 'g'), Placeholders.FirstTab) + .replace(new RegExp(/\${2:second}/, 'g'), Placeholders.SecondTab) + .replace(new RegExp(/\${3:third}/, 'g'), Placeholders.ThirdTab) + .replace( + new RegExp(/\${1\/(.*)\/${1:\/capitalize}\/}/, 'g'), + Placeholders.Capitalize, + ); +}; +export default revertSnippetPlaceholders; diff --git a/src/helpers/snippetSearch.ts b/src/helpers/snippetSearch.ts new file mode 100644 index 0000000..bb2855a --- /dev/null +++ b/src/helpers/snippetSearch.ts @@ -0,0 +1,41 @@ +import { readFileSync } from 'fs'; +import { SnippetString, window } from 'vscode'; + +import { parseSnippet } from './formatters'; +import { Snippet } from './generateSnippets'; + +const snippetSearch = async () => { + const { showQuickPick, activeTextEditor } = window; + + const snippets = readFileSync( + __dirname + '/../snippets/generated.json', + 'utf8', + ); + + const snippetsArray = Object.entries(JSON.parse(snippets)) as [ + string, + Snippet, + ][]; + + const items = snippetsArray.map( + ([shortDescription, { body, description, prefix: label }]) => ({ + body, + description: description || shortDescription, + label, + }), + ); + + const rawSnippet = await showQuickPick(items, { + matchOnDescription: true, + matchOnDetail: true, + placeHolder: 'Search snippet by prefix or description', + }); + + const body = rawSnippet ? parseSnippet(rawSnippet.body) : ''; + + if (activeTextEditor) { + activeTextEditor.insertSnippet(new SnippetString(body)); + } +}; + +export default snippetSearch; diff --git a/src/index.d b/src/index.d new file mode 100644 index 0000000..e2f4a7c --- /dev/null +++ b/src/index.d @@ -0,0 +1,15 @@ +--- +nav: + title: 工具 + path: /other + second: + title: 规范工具 + order: 2 +group: + title: snippets 代码片段 + order: 4 +--- + +# snippets 代码片段 + + diff --git a/src/index.md b/src/index.md new file mode 100644 index 0000000..560739a --- /dev/null +++ b/src/index.md @@ -0,0 +1,11 @@ +--- +nav: + title: 工具 + path: /other +group: + title: 其它 +title: 代码片段 +toc: content +--- + + diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..1436741 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,47 @@ +import { + commands, + ConfigurationChangeEvent, + ExtensionContext, + window, + workspace, +} from 'vscode'; + +import generateSnippets from './helpers/generateSnippets'; +import snippetSearch from './helpers/snippetSearch'; +import generatedSnippets from '../snippets/snippets.json'; + +const showRestartMessage = async ({ + affectsConfiguration, +}: ConfigurationChangeEvent) => { + if (affectsConfiguration('reactSnippets')) { + await generateSnippets(); + setTimeout(() => { + window + .showWarningMessage( + 'React Snippets: Please restart VS Code to apply snippet formatting changes', + 'Restart VS Code', + 'Ignore', + ) + .then((action?: string) => { + if (action === 'Restart VS Code') { + commands.executeCommand('workbench.action.reloadWindow'); + } + }); + }, 1000); + } +}; + +export async function activate(context: ExtensionContext) { + workspace.onDidChangeConfiguration(showRestartMessage); + if (JSON.stringify(generatedSnippets).length < 10) { + await generateSnippets(); + } + const snippetSearchCommand = commands.registerCommand( + 'reactSnippets.search', + snippetSearch, + ); + + context.subscriptions.push(snippetSearchCommand); +} + +export function deactivate() {} diff --git a/src/sourceSnippets/components.ts b/src/sourceSnippets/components.ts new file mode 100644 index 0000000..09ef578 --- /dev/null +++ b/src/sourceSnippets/components.ts @@ -0,0 +1,365 @@ +import { Placeholders, SnippetMapping } from '../types'; + +import { + exportDefault, + innerComponent, + innerComponentReturn, + react, + reactComponent, + reactComponentWithReduxConnect, + reactPropTypes, + reactPureComponent, + reactWithMemo, + reactWithReduxConnect, + reduxComponentExport, +} from './sharedSnippets'; + +type ComponentMappings = { + reactArrowFunctionComponent: 'rafc'; + reactArrowFunctionComponentWithPropTypes: 'rafcp'; + reactArrowFunctionExportComponent: 'rafce'; + reactClassComponentPropTypes: 'rccp'; + reactClassComponentRedux: 'rcredux'; + reactClassComponentReduxPropTypes: 'rcreduxp'; + reactClassComponent: 'rcc'; + reactClassExportComponent: 'rce'; + reactClassExportComponentWithPropTypes: 'rcep'; + reactClassExportPureComponent: 'rpce'; + reactClassPureComponent: 'rpc'; + reactClassPureComponentWithPropTypes: 'rpcp'; + reactFunctionMemoComponent: 'rmc'; + reactFunctionMemoComponentWithPropTypes: 'rmcp'; + reactFunctionalComponentRedux: 'rfcredux'; + reactFunctionalComponentReduxPropTypes: 'rfcreduxp'; + reactFunctionalComponent: 'rfc'; + reactFunctionalComponentWithPropTypes: 'rfcp'; + reactFunctionalExportComponent: 'rfce'; +}; + +export type ComponentsSnippet = SnippetMapping; + +const reactClassComponent: ComponentsSnippet = { + key: 'reactClassComponent', + prefix: 'rcc', + body: [ + ...reactComponent, + '', + `export default class ${Placeholders.FileName} extends Component {`, + ...innerComponentReturn, + '}', + '', + ], + description: 'Creates a React component class with ES7 module system', +}; + +const reactClassExportComponent: ComponentsSnippet = { + key: 'reactClassExportComponent', + prefix: 'rce', + body: [ + ...reactComponent, + '', + `export class ${Placeholders.FileName} extends Component {`, + ...innerComponentReturn, + '}', + ...exportDefault, + ], + description: 'Creates a React component class with ES7 module system', +}; + +const reactFunctionalExportComponent: ComponentsSnippet = { + key: 'reactFunctionalExportComponent', + prefix: 'rfce', + body: [ + ...react, + '', + `function ${Placeholders.FileName}() {`, + ...innerComponent, + '}', + ...exportDefault, + ], + description: 'Creates a React Functional Component with ES7 module system', +}; + +const reactFunctionalComponent: ComponentsSnippet = { + key: 'reactFunctionalComponent', + prefix: 'rfc', + body: [ + ...react, + '', + `export default function ${Placeholders.FileName}() {`, + ...innerComponent, + '}', + '', + ], + description: 'Creates a React Functional Component with ES7 module system', +}; + +const reactFunctionalComponentWithPropTypes: ComponentsSnippet = { + key: 'reactFunctionalComponentWithPropTypes', + prefix: 'rfcp', + body: [ + ...reactPropTypes, + '', + `function ${Placeholders.FileName}(props) {`, + ...innerComponent, + '}', + '', + `${Placeholders.FileName}.propTypes = {}`, + ...exportDefault, + '', + ], + description: + 'Creates a React Functional Component with ES7 module system with PropTypes', +}; + +const reactArrowFunctionExportComponent: ComponentsSnippet = { + key: 'reactArrowFunctionExportComponent', + prefix: 'rafce', + body: [ + ...react, + '', + `const ${Placeholders.FileName} = () => {`, + ...innerComponent, + '}', + ...exportDefault, + ], + description: + 'Creates a React Arrow Function Component with ES7 module system', +}; + +const reactArrowFunctionComponent: ComponentsSnippet = { + key: 'reactArrowFunctionComponent', + prefix: 'rafc', + body: [ + ...react, + '', + `export const ${Placeholders.FileName} = () => {`, + ...innerComponent, + '}', + '', + ], + description: + 'Creates a React Arrow Function Component with ES7 module system', +}; + +const reactArrowFunctionComponentWithPropTypes: ComponentsSnippet = { + key: 'reactArrowFunctionComponentWithPropTypes', + prefix: 'rafcp', + body: [ + ...reactPropTypes, + '', + `const ${Placeholders.FileName} = props => {`, + ...innerComponent, + '}', + '', + `${Placeholders.FileName}.propTypes = {}`, + ...exportDefault, + ], + description: + 'Creates a React Arrow Function Component with ES7 module system with PropTypes', +}; + +const reactClassExportComponentWithPropTypes: ComponentsSnippet = { + key: 'reactClassExportComponentWithPropTypes', + prefix: 'rcep', + body: [ + "import PropTypes from 'prop-types'", + ...reactComponent, + '', + `export class ${Placeholders.FileName} extends Component {`, + ' static propTypes = {}', + '', + ...innerComponentReturn, + '}', + ...exportDefault, + ], + description: 'Creates a React component class with ES7 module system', +}; + +const reactClassPureComponent: ComponentsSnippet = { + key: 'reactClassPureComponent', + prefix: 'rpc', + body: [ + ...reactPureComponent, + '', + `export default class ${Placeholders.FileName} extends PureComponent {`, + ...innerComponentReturn, + '}', + '', + ], + description: 'Creates a React pure component class with ES7 module system', +}; + +const reactClassExportPureComponent: ComponentsSnippet = { + key: 'reactClassExportPureComponent', + prefix: 'rpce', + body: [ + ...reactPureComponent, + '', + `export class ${Placeholders.FileName} extends PureComponent {`, + ...innerComponentReturn, + '}', + ...exportDefault, + ], + description: + 'Creates a React pure component class with ES7 module system export', +}; + +const reactClassPureComponentWithPropTypes: ComponentsSnippet = { + key: 'reactClassPureComponentWithPropTypes', + prefix: 'rpcp', + body: [ + "import PropTypes from 'prop-types'", + ...reactPureComponent, + '', + `export default class ${Placeholders.FileName} extends PureComponent {`, + ' static propTypes = {}', + '', + ...innerComponentReturn, + '}', + '', + ], + description: 'Creates a React component class with ES7 module system', +}; + +const reactFunctionMemoComponent: ComponentsSnippet = { + key: 'reactFunctionMemoComponent', + prefix: 'rmc', + body: [ + ...reactWithMemo, + '', + `const ${Placeholders.FileName} = memo(() => {`, + ...innerComponent, + '})', + ...exportDefault, + ], + description: 'Creates a React Memo Function Component with ES7 module system', +}; + +const reactFunctionMemoComponentWithPropTypes: ComponentsSnippet = { + key: 'reactFunctionMemoComponentWithPropTypes', + prefix: 'rmcp', + body: [ + "import PropTypes from 'prop-types'", + ...reactWithMemo, + '', + `const ${Placeholders.FileName} = memo((props) => {`, + ...innerComponent, + '})', + '', + `${Placeholders.FileName}.propTypes = {}`, + ...exportDefault, + ], + description: + 'Creates a React Memo Function Component with ES7 module system with PropTypes', +}; + +const reactClassComponentPropTypes: ComponentsSnippet = { + key: 'reactClassComponentPropTypes', + prefix: 'rccp', + body: [ + "import PropTypes from 'prop-types'", + ...reactComponent, + '', + `export default class ${Placeholders.FileName} extends Component {`, + ` static propTypes = {${Placeholders.SecondTab}: ${Placeholders.ThirdTab}}`, + '', + ...innerComponentReturn, + '}', + '', + ], + description: + 'Creates a React component class with PropTypes and ES7 module system', +}; + +const reactClassComponentRedux: ComponentsSnippet = { + key: 'reactClassComponentRedux', + prefix: 'rcredux', + body: [ + ...reactComponentWithReduxConnect, + '', + `export class ${Placeholders.FileName} extends Component {`, + ...innerComponentReturn, + '}', + ...reduxComponentExport, + ], + description: + 'Creates a React component class with connected redux and ES7 module system', +}; + +const reactClassComponentReduxPropTypes: ComponentsSnippet = { + key: 'reactClassComponentReduxPropTypes', + prefix: 'rcreduxp', + body: [ + "import PropTypes from 'prop-types'", + ...reactComponentWithReduxConnect, + '', + `export class ${Placeholders.FileName} extends Component {`, + ' static propTypes = {', + ` ${Placeholders.SecondTab}: ${Placeholders.ThirdTab}`, + ' }', + '', + ...innerComponentReturn, + '}', + ...reduxComponentExport, + ], + description: + 'Creates a React component class with PropTypes with connected redux and ES7 module system', +}; + +const reactFunctionalComponentRedux: ComponentsSnippet = { + key: 'reactFunctionalComponentRedux', + prefix: 'rfcredux', + body: [ + ...reactWithReduxConnect, + '', + `export const ${Placeholders.FileName} = (props) => {`, + ...innerComponent, + '}', + ...reduxComponentExport, + ], + description: + 'Creates a React functional component with connected redux and ES7 module system', +}; + +const reactFunctionalComponentReduxPropTypes: ComponentsSnippet = { + key: 'reactFunctionalComponentReduxPropTypes', + prefix: 'rfcreduxp', + body: [ + "import PropTypes from 'prop-types'", + ...reactWithReduxConnect, + '', + `export const ${Placeholders.FileName} = (props) => {`, + ...innerComponent, + '}', + '', + `${Placeholders.FileName}.propTypes = {`, + ` ${Placeholders.SecondTab}: PropTypes.${Placeholders.ThirdTab}`, + '}', + ...reduxComponentExport, + ], + description: + 'DEPRECATED: Creates a React functional component with PropTypes with connected redux and ES7 module system', +}; + +export default [ + reactArrowFunctionComponent, + reactArrowFunctionComponentWithPropTypes, + reactArrowFunctionExportComponent, + reactClassComponent, + reactClassComponentPropTypes, + reactClassComponentRedux, + reactClassComponentReduxPropTypes, + reactClassExportComponent, + reactClassExportComponentWithPropTypes, + reactClassExportPureComponent, + reactClassPureComponent, + reactClassPureComponentWithPropTypes, + reactFunctionMemoComponent, + reactFunctionMemoComponentWithPropTypes, + reactFunctionalComponent, + reactFunctionalComponentRedux, + reactFunctionalComponentReduxPropTypes, + reactFunctionalComponentWithPropTypes, + reactFunctionalExportComponent, +]; diff --git a/src/sourceSnippets/console.ts b/src/sourceSnippets/console.ts new file mode 100644 index 0000000..dec49de --- /dev/null +++ b/src/sourceSnippets/console.ts @@ -0,0 +1,162 @@ +import { Placeholders, SnippetMapping } from '../types'; + +type ConsoleMapping = { + consoleAssert: 'cas'; + consoleClear: 'ccl'; + consoleCount: 'cco'; + consoleDir: 'cdi'; + consoleError: 'cer'; + consoleGroup: 'cgr'; + consoleGroupEnd: 'cge'; + consoleLog: 'clg'; + consoleTrace: 'ctr'; + consoleLogObject: 'clo'; + consoleLogJson: 'clj'; + consoleTime: 'ctm'; + consoleTimeEnd: 'cte'; + consoleWarn: 'cwa'; + consoleInfo: 'cin'; + consoleTable: 'ctl'; +}; + +export type ConsoleSnippet = SnippetMapping; + +const consoleAssert: ConsoleSnippet = { + key: 'consoleAssert', + prefix: 'cas', + body: [`console.assert(${Placeholders.FirstTab}, ${Placeholders.SecondTab})`], + description: + 'If the specified expression is false, the message is written to the console along with a stack trace', +}; + +const consoleClear: ConsoleSnippet = { + key: 'consoleClear', + prefix: 'ccl', + body: ['console.clear()'], + description: 'Clears the console', +}; + +const consoleCount: ConsoleSnippet = { + key: 'consoleCount', + prefix: 'cco', + body: [`console.count(${Placeholders.FirstTab})`], + description: + 'Writes the the number of times that count() has been invoked at the same line and with the same label', +}; + +const consoleDir: ConsoleSnippet = { + key: 'consoleDir', + prefix: 'cdi', + body: [`console.dir(${Placeholders.FirstTab})`], + description: 'Prints a JavaScript representation of the specified object', +}; + +const consoleError: ConsoleSnippet = { + key: 'consoleError', + prefix: 'cer', + body: [`console.error(${Placeholders.FirstTab})`], + description: + 'Displays a message in the console and also includes a stack trace from where the method was called', +}; + +const consoleGroup: ConsoleSnippet = { + key: 'consoleGroup', + prefix: 'cgr', + body: [`console.group('${Placeholders.FirstTab}')`], + description: + 'Groups and indents all following output by an additional level, until console.groupEnd() is called.', +}; + +const consoleGroupEnd: ConsoleSnippet = { + key: 'consoleGroupEnd', + prefix: 'cge', + body: ['console.groupEnd()'], + description: 'Closes out the corresponding console.group().', +}; + +const consoleLog: ConsoleSnippet = { + key: 'consoleLog', + prefix: 'clg', + body: [`console.log(${Placeholders.FirstTab})`], + description: 'Displays a message in the console', +}; + +const consoleTrace: ConsoleSnippet = { + key: 'consoleTrace', + prefix: 'ctr', + body: [`console.trace(${Placeholders.FirstTab})`], + description: + 'Prints a stack trace from the point where the method was called', +}; + +const consoleLogObject: ConsoleSnippet = { + key: 'consoleLogObject', + prefix: 'clo', + body: [`console.log('${Placeholders.FirstTab}', ${Placeholders.FirstTab})`], + description: 'Logs property with name.', +}; + +const consoleLogJson: ConsoleSnippet = { + key: 'consoleLogJson', + prefix: 'clj', + body: [ + `console.log('${Placeholders.FirstTab}', JSON.stringify(${Placeholders.FirstTab}, null, 2))`, + ], + description: 'Logs stringified JSON property with name.', +}; + +const consoleTime: ConsoleSnippet = { + key: 'consoleTime', + prefix: 'ctm', + body: [`console.time('${Placeholders.FirstTab}')`], + description: 'Console time wrapper', +}; + +const consoleTimeEnd: ConsoleSnippet = { + key: 'consoleTimeEnd', + prefix: 'cte', + body: [`console.timeEnd('${Placeholders.FirstTab}')`], + description: 'Console time end wrapper', +}; + +const consoleWarn: ConsoleSnippet = { + key: 'consoleWarn', + prefix: 'cwa', + body: [`console.warn(${Placeholders.FirstTab})`], + description: + 'Displays a message in the console but also displays a yellow warning icon along with the logged message', +}; + +const consoleInfo: ConsoleSnippet = { + key: 'consoleInfo', + prefix: 'cin', + body: [`console.info(${Placeholders.FirstTab})`], + description: + 'Displays a message in the console but also displays a blue information icon along with the logged message', +}; + +const consoleTable: ConsoleSnippet = { + key: 'consoleTable', + prefix: 'ctl', + body: [`console.table([${Placeholders.FirstTab}])`], + description: 'Logs table to console', +}; + +export default [ + consoleAssert, + consoleClear, + consoleCount, + consoleDir, + consoleError, + consoleGroup, + consoleGroupEnd, + consoleLog, + consoleTrace, + consoleLogObject, + consoleLogJson, + consoleTime, + consoleTimeEnd, + consoleWarn, + consoleInfo, + consoleTable, +]; diff --git a/src/sourceSnippets/hooks.ts b/src/sourceSnippets/hooks.ts new file mode 100644 index 0000000..d8a0377 --- /dev/null +++ b/src/sourceSnippets/hooks.ts @@ -0,0 +1,122 @@ +import { Placeholders, SnippetMapping } from '../types'; + +type HookMappings = { + useState: 'useStateSnippet'; + useCallback: 'useCallbackSnippet'; + useContext: 'useContextSnippet'; + useEffect: 'useEffectSnippet'; + useImperativeHandle: 'useImperativeHandleSnippet'; + useLayoutEffect: 'useLayoutEffectSnippet'; + useMemo: 'useMemoSnippet'; + useReducer: 'useReducerSnippet'; + useRef: 'useRefSnippet'; +}; + +export type HooksSnippet = SnippetMapping; + +const useEffect: HooksSnippet = { + key: 'useEffect', + prefix: 'useEffectSnippet', + body: [ + 'useEffect(() => {', + ` ${Placeholders.FirstTab}`, + '', + ' return () => {', + ` ${Placeholders.SecondTab}`, + ' }', + `}, [${Placeholders.ThirdTab}])`, + '', + ], +}; + +const useContext: HooksSnippet = { + key: 'useContext', + prefix: 'useContextSnippet', + body: [ + `const ${Placeholders.FirstTab} = useContext(${Placeholders.SecondTab})`, + ], +}; + +const useState: HooksSnippet = { + key: 'useState', + prefix: 'useStateSnippet', + body: [ + `const [${Placeholders.FirstTab}, set${Placeholders.Capitalize}] = useState(${Placeholders.SecondTab})`, + ], +}; + +const useReducer: HooksSnippet = { + key: 'useReducer', + prefix: 'useReducerSnippet', + body: [ + `const [state, dispatch] = useReducer(${Placeholders.FirstTab}, ${Placeholders.SecondTab}, ${Placeholders.ThirdTab})`, + ], +}; + +const useCallback: HooksSnippet = { + key: 'useCallback', + prefix: 'useCallbackSnippet', + body: [ + 'useCallback(', + ' () => {', + ` ${Placeholders.FirstTab}`, + ' },', + ` [${Placeholders.SecondTab}],`, + ')', + '', + ], +}; + +const useMemo: HooksSnippet = { + key: 'useMemo', + prefix: 'useMemoSnippet', + body: [ + `useMemo(() => ${Placeholders.FirstTab}, [${Placeholders.SecondTab}])`, + ], +}; + +const useRef: HooksSnippet = { + key: 'useRef', + prefix: 'useRefSnippet', + body: [`const ${Placeholders.FirstTab} = useRef(${Placeholders.SecondTab})`], +}; + +const useImperativeHandle: HooksSnippet = { + key: 'useImperativeHandle', + prefix: 'useImperativeHandleSnippet', + body: [ + 'useImperativeHandle(', + ` ${Placeholders.FirstTab},`, + ' () => {', + ` ${Placeholders.SecondTab}`, + ' },', + ` [${Placeholders.ThirdTab}],`, + ')', + ], +}; + +const useLayoutEffect: HooksSnippet = { + key: 'useLayoutEffect', + prefix: 'useLayoutEffectSnippet', + body: [ + 'useLayoutEffect(() => {', + ` ${Placeholders.FirstTab}`, + '', + ' return () => {', + ` ${Placeholders.SecondTab}`, + ' };', + `}, [${Placeholders.ThirdTab}])`, + ], +}; + +export default [ + useCallback, + useContext, + useEffect, + useImperativeHandle, + useLayoutEffect, + useMemo, + useReducer, + useRef, + useState, +]; diff --git a/src/sourceSnippets/imports.ts b/src/sourceSnippets/imports.ts new file mode 100644 index 0000000..f28281b --- /dev/null +++ b/src/sourceSnippets/imports.ts @@ -0,0 +1,200 @@ +import { Placeholders, SnippetMapping } from '../types'; + +import { reactWithMemo } from './sharedSnippets'; + +type ImportsMappings = { + import: 'imp'; + importAs: 'ima'; + importBrowserRouter: 'imbr'; + importBrowserRouterWithRouteAndNavLink: 'imrr'; + importDestructing: 'imd'; + importEverything: 'ime'; + importNoModuleName: 'imn'; + importPropTypes: 'impt'; + importReact: 'imr'; + importReactDom: 'imrd'; + importReactWithComponent: 'imrc'; + importReactWithComponentAndPropTypes: 'imrcp'; + importReactWithMemo: 'imrm'; + importReactWithMemoAndPropTypes: 'imrmp'; + importReactWithPureComponent: 'imrpc'; + importReactWithPureComponentAndPropTypes: 'imrpcp'; + importReduxConnect: 'redux'; + importRouterLink: 'imbrl'; + importRouterNavLink: 'imbrnl'; + importRouterSetup: 'imbrc'; + importRouterSwitch: 'imbrs'; +}; + +export type ImportsSnippet = SnippetMapping; + +/** + * react, react-dom & prop-types + */ +const importReact: ImportsSnippet = { + key: 'importReact', + prefix: 'imr', + body: ["import React from 'react'"], +}; + +const importReactDom: ImportsSnippet = { + key: 'importReactDom', + prefix: 'imrd', + body: ["import ReactDOM from 'react-dom'"], +}; + +const importReactWithComponent: ImportsSnippet = { + key: 'importReactWithComponent', + prefix: 'imrc', + body: ["import React, { Component } from 'react'"], +}; + +const importReactWithComponentAndPropTypes: ImportsSnippet = { + key: 'importReactWithComponentAndPropTypes', + prefix: 'imrcp', + body: [ + "import React, { Component } from 'react'", + "import PropTypes from 'prop-types'", + '', + ], +}; + +const importReactWithPureComponent: ImportsSnippet = { + key: 'importReactWithPureComponent', + prefix: 'imrpc', + body: ["import React, { PureComponent } from 'react'"], +}; + +const importReactWithPureComponentAndPropTypes: ImportsSnippet = { + key: 'importReactWithPureComponentAndPropTypes', + prefix: 'imrpcp', + body: [ + "import React, { PureComponent } from 'react'", + "import PropTypes from 'prop-types'", + '', + ], +}; + +const importReactWithMemo: ImportsSnippet = { + key: 'importReactWithMemo', + prefix: 'imrm', + body: reactWithMemo, +}; + +const importReactWithMemoAndPropTypes: ImportsSnippet = { + key: 'importReactWithMemoAndPropTypes', + prefix: 'imrmp', + body: [...reactWithMemo, "import PropTypes from 'prop-types'", ''], +}; + +const importPropTypes: ImportsSnippet = { + key: 'importPropTypes', + prefix: 'impt', + body: ["import PropTypes from 'prop-types'"], +}; + +/** + * react-router + */ + +const importBrowserRouter: ImportsSnippet = { + key: 'importBrowserRouter', + prefix: 'imbr', + body: ["import { BrowserRouter as Router } from 'react-router-dom'"], +}; + +const importBrowserRouterWithRouteAndNavLink: ImportsSnippet = { + key: 'importBrowserRouterWithRouteAndNavLink', + prefix: 'imrr', + body: [ + "import { BrowserRouter as Router, Route, NavLink } from 'react-router-dom'", + '', + ], +}; + +const importRouterSetup: ImportsSnippet = { + key: 'importRouterSetup', + prefix: 'imbrc', + body: ["import { Route, Switch, NavLink, Link } from 'react-router-dom'"], +}; + +const importRouterSwitch: ImportsSnippet = { + key: 'importRouterSwitch', + prefix: 'imbrs', + body: ["import { Switch } from 'react-router-dom'"], +}; + +const importRouterLink: ImportsSnippet = { + key: 'importRouterLink', + prefix: 'imbrl', + body: ["import { Link } from 'react-router-dom'"], +}; + +const importRouterNavLink: ImportsSnippet = { + key: 'importRouterNavLink', + prefix: 'imbrnl', + body: ["import { NavLink } from 'react-router-dom'"], +}; + +/** + * Others + */ + +const importSnippet: ImportsSnippet = { + key: 'import', + prefix: 'imp', + body: [`import ${Placeholders.SecondTab} from '${Placeholders.FirstTab}'`], +}; + +const importNoModuleName: ImportsSnippet = { + key: 'importNoModuleName', + prefix: 'imn', + body: [`import '${Placeholders.FirstTab}'`], +}; + +const importDestructing: ImportsSnippet = { + key: 'importDestructing', + prefix: 'imd', + body: [ + `import { ${Placeholders.SecondTab} } from '${Placeholders.FirstTab}'`, + ], +}; + +const importEverything: ImportsSnippet = { + key: 'importEverything', + prefix: 'ime', + body: [ + `import * as ${Placeholders.SecondTab} from '${Placeholders.FirstTab}'`, + ], +}; + +const importAs: ImportsSnippet = { + key: 'importAs', + prefix: 'ima', + body: [ + `import { ${Placeholders.SecondTab} as ${Placeholders.ThirdTab} } from '${Placeholders.FirstTab}'`, + ], +}; + +export default [ + importAs, + importBrowserRouter, + importBrowserRouterWithRouteAndNavLink, + importDestructing, + importEverything, + importNoModuleName, + importPropTypes, + importReact, + importReactDom, + importReactWithComponent, + importReactWithComponentAndPropTypes, + importReactWithMemo, + importReactWithMemoAndPropTypes, + importReactWithPureComponent, + importReactWithPureComponentAndPropTypes, + importRouterLink, + importRouterNavLink, + importRouterSetup, + importRouterSwitch, + importSnippet, +]; diff --git a/src/sourceSnippets/others.ts b/src/sourceSnippets/others.ts new file mode 100644 index 0000000..76bf1db --- /dev/null +++ b/src/sourceSnippets/others.ts @@ -0,0 +1,451 @@ +import { Placeholders, SnippetMapping } from '../types'; + +type OthersMapping = { + commentBigBlock: 'cmmb'; + anonymousFunction: 'anfn'; + bindThis: 'bnd'; + classConstructor: 'rconst'; + componentDidMount: 'cdm'; + componentDidUpdate: 'cdup'; + componentProps: 'props'; + componentSetStateFunc: 'ssf'; + componentSetStateObject: 'sst'; + componentState: 'state'; + componentWillUnmount: 'cwun'; + createContext: 'rcontext'; + createRef: 'cref'; + destructProps: 'cp'; + destructState: 'cs'; + destructingArray: 'dar'; + destructingObject: 'dob'; + emptyState: 'est'; + exportAs: 'exa'; + exportDefault: 'exp'; + exportDefaultFunction: 'edf'; + exportDefaultNamedFunction: 'ednf'; + exportDestructing: 'exd'; + exportNamedFunction: 'enf'; + forEach: 'fre'; + forIn: 'fin'; + forOf: 'fof'; + getDerivedStateFromProps: 'gdsfp'; + getSnapshotBeforeUpdate: 'gsbu'; + hocComponent: 'hoc'; + hocComponentWithRedux: 'hocredux'; + method: 'met'; + namedFunction: 'nfn'; + promise: 'prom'; + propertyGet: 'pge'; + propertySet: 'pse'; + setInterval: 'sti'; + setTimeOut: 'sto'; + shouldComponentUpdate: 'scu'; + typeofSnippet: 'tpf'; +}; + +export type OthersSnippet = SnippetMapping; + +const exportDefault: OthersSnippet = { + key: 'exportDefault', + prefix: 'exp', + body: [`export default ${Placeholders.FirstTab}`], +}; + +const exportDestructing: OthersSnippet = { + key: 'exportDestructing', + prefix: 'exd', + body: [ + `export { ${Placeholders.SecondTab} } from '${Placeholders.FirstTab}'`, + ], +}; + +const exportAs: OthersSnippet = { + key: 'exportAs', + prefix: 'exa', + body: [ + `export { ${Placeholders.SecondTab} as ${Placeholders.ThirdTab} } from '${Placeholders.FirstTab}'`, + ], +}; + +const exportNamedFunction: OthersSnippet = { + key: 'exportNamedFunction', + prefix: 'enf', + body: [ + `export const ${Placeholders.FirstTab} = (${Placeholders.SecondTab}) => {${Placeholders.ThirdTab}}`, + ], + description: 'Export named function', +}; + +const exportDefaultFunction: OthersSnippet = { + key: 'exportDefaultFunction', + prefix: 'edf', + body: [ + `export default (${Placeholders.FirstTab}) => {${Placeholders.SecondTab}}`, + ], + description: 'Export default function', +}; + +const exportDefaultNamedFunction: OthersSnippet = { + key: 'exportDefaultNamedFunction', + prefix: 'ednf', + body: [ + `export default function ${Placeholders.FirstTab}(${Placeholders.SecondTab}) {${Placeholders.ThirdTab}}`, + ], + description: 'Export default named function', +}; + +const method: OthersSnippet = { + key: 'method', + prefix: 'met', + body: [ + `${Placeholders.FirstTab} = (${Placeholders.SecondTab}) => {${Placeholders.ThirdTab}}`, + ], + description: 'Creates a method inside a class', +}; + +const propertyGet: OthersSnippet = { + key: 'propertyGet', + prefix: 'pge', + body: [ + `get ${Placeholders.FirstTab}() {`, + ` return this.${Placeholders.SecondTab}`, + '}', + ], + description: 'Creates a getter property inside a class', +}; + +const propertySet: OthersSnippet = { + key: 'propertySet', + prefix: 'pse', + body: [ + `set ${Placeholders.FirstTab}(${Placeholders.SecondTab}) {${Placeholders.ThirdTab}}`, + ], + description: 'Creates a setter property inside a class', +}; + +const forEach: OthersSnippet = { + key: 'forEach', + prefix: 'fre', + body: [ + `${Placeholders.FirstTab}.forEach(${Placeholders.SecondTab} => {${Placeholders.ThirdTab}})`, + ], + description: 'Creates a forEach statement', +}; + +const forOf: OthersSnippet = { + key: 'forOf', + prefix: 'fof', + body: [ + `for(let ${Placeholders.FirstTab} of ${Placeholders.SecondTab}) {${Placeholders.ThirdTab}}`, + ], + description: 'Iterating over property names of iterable objects', +}; + +const forIn: OthersSnippet = { + key: 'forIn', + prefix: 'fin', + body: [ + `for(let ${Placeholders.FirstTab} in ${Placeholders.SecondTab}) {${Placeholders.ThirdTab}}`, + ], + description: 'Iterating over property values of iterable objects', +}; + +const anonymousFunction: OthersSnippet = { + key: 'anonymousFunction', + prefix: 'anfn', + body: [`(${Placeholders.FirstTab}) => { ${Placeholders.SecondTab} }`], + description: 'Creates an anonymous function', +}; + +const namedFunction: OthersSnippet = { + key: 'namedFunction', + prefix: 'nfn', + body: [ + `const ${Placeholders.FirstTab} = (${Placeholders.SecondTab}) => { ${Placeholders.ThirdTab} }`, + ], + description: 'Creates a named function', +}; + +const destructingObject: OthersSnippet = { + key: 'destructingObject', + prefix: 'dob', + body: [`const {${Placeholders.SecondTab}} = ${Placeholders.FirstTab}`], + description: 'Creates and assigns a local variable using object destructing', +}; + +const destructingArray: OthersSnippet = { + key: 'destructingArray', + prefix: 'dar', + body: [`const [${Placeholders.SecondTab}] = ${Placeholders.FirstTab}`], + description: 'Creates and assigns a local variable using array destructing', +}; + +const setInterval: OthersSnippet = { + key: 'setInterval', + prefix: 'sti', + body: [ + `setInterval(() => { ${Placeholders.FirstTab} }, ${Placeholders.SecondTab})`, + ], + description: 'Executes the given function at specified intervals', +}; + +const setTimeOut: OthersSnippet = { + key: 'setTimeOut', + prefix: 'sto', + body: [ + `setTimeout(() => { ${Placeholders.FirstTab} }, ${Placeholders.SecondTab})`, + ], + description: 'Executes the given function after the specified delay', +}; + +const promise: OthersSnippet = { + key: 'promise', + prefix: 'prom', + body: [ + `return new Promise((resolve, reject) => { ${Placeholders.FirstTab} })`, + ], + description: 'Creates and returns a new Promise in the standard ES7 syntax', +}; + +const destructProps: OthersSnippet = { + key: 'destructProps', + prefix: 'cp', + body: [`const { ${Placeholders.FirstTab} } = this.props`], + description: 'Creates and assigns a local variable using props destructing', +}; + +const destructState: OthersSnippet = { + key: 'destructState', + prefix: 'cs', + body: [`const { ${Placeholders.FirstTab} } = this.state`], + description: 'Creates and assigns a local variable using state destructing', +}; + +const classConstructor: OthersSnippet = { + key: 'classConstructor', + prefix: 'rconst', + body: [ + 'constructor(props) {', + ' super(props)', + '', + ' this.state = {', + ` ${Placeholders.FirstTab}`, + ' }', + '}', + ], + description: + "Adds a default constructor for it('', () => {})the class that contains props as arguments", +}; + +const emptyState: OthersSnippet = { + key: 'emptyState', + prefix: 'est', + body: [`state = { ${Placeholders.FirstTab} }`], + description: 'Creates empty state object. To be used in a constructor.', +}; + +const componentDidMount: OthersSnippet = { + key: 'componentDidMount', + prefix: 'cdm', + body: [`componentDidMount() { ${Placeholders.FirstTab} }`], + description: + 'Invoked once, only on the client (not on the server), immediately after the initial rendering occurs.', +}; + +const shouldComponentUpdate: OthersSnippet = { + key: 'shouldComponentUpdate', + prefix: 'scu', + body: [ + `shouldComponentUpdate(nextProps, nextState) { ${Placeholders.FirstTab} }`, + ], + description: + 'Invoked before rendering when new props or state are being received. ', +}; + +const componentDidUpdate: OthersSnippet = { + key: 'componentDidUpdate', + prefix: 'cdup', + body: [ + `componentDidUpdate(prevProps, prevState) { ${Placeholders.FirstTab}} `, + ], + description: + "Invoked immediately after the component's updates are flushed to the DOM.", +}; + +const componentWillUnmount: OthersSnippet = { + key: 'componentWillUnmount', + prefix: 'cwun', + body: [`componentWillUnmount() {${Placeholders.FirstTab} }`], + description: + 'Invoked immediately before a component is unmounted from the DOM.', +}; + +const getDerivedStateFromProps: OthersSnippet = { + key: 'getDerivedStateFromProps', + prefix: 'gdsfp', + body: [ + `static getDerivedStateFromProps(props, state) {${Placeholders.FirstTab}}`, + ], + description: + 'Invoked right before calling the render method, both on the initial mount and on subsequent updates.', +}; + +const getSnapshotBeforeUpdate: OthersSnippet = { + key: 'getSnapshotBeforeUpdate', + prefix: 'gsbu', + body: [ + `getSnapshotBeforeUpdate = (prevProps, prevState) => {${Placeholders.FirstTab}}`, + ], + description: + 'Called right before mutations are made (e.g. before the DOM is updated)', +}; + +const createContext: OthersSnippet = { + key: 'createContext', + prefix: 'rcontext', + body: [`const ${Placeholders.FirstTab} = React.createContext()`], + description: 'Create React context', +}; + +const createRef: OthersSnippet = { + key: 'createRef', + prefix: 'cref', + body: [`this.${Placeholders.FirstTab}Ref = React.createRef()`], + description: 'Create ref statement used inside constructor', +}; + +const componentSetStateObject: OthersSnippet = { + key: 'componentSetStateObject', + prefix: 'sst', + body: [`this.setState({${Placeholders.FirstTab}})`], + description: 'Performs a shallow merge of nextState into current state', +}; + +const componentSetStateFunc: OthersSnippet = { + key: 'componentSetStateFunc', + prefix: 'ssf', + body: [ + `this.setState((state, props) => { return { ${Placeholders.FirstTab} }})`, + ], + description: 'Performs a shallow merge of nextState into current state', +}; + +const componentProps: OthersSnippet = { + key: 'componentProps', + prefix: 'props', + body: [`this.props.${Placeholders.FirstTab}`], + description: "Access component's props", +}; + +const componentState: OthersSnippet = { + key: 'componentState', + prefix: 'state', + body: [`this.state.${Placeholders.FirstTab}`], +}; + +const bindThis: OthersSnippet = { + key: 'bindThis', + prefix: 'bnd', + body: [ + `this.${Placeholders.FirstTab} = this.${Placeholders.FirstTab}.bind(this)`, + ], + description: 'Binds this to a method', +}; + +const commentBigBlock: OthersSnippet = { + key: 'commentBigBlock', + prefix: 'cmmb', + body: ['/**', ` * ${Placeholders.FirstTab}`, ' */'], +}; + +const hocComponentWithRedux: OthersSnippet = { + key: 'hocComponentWithRedux', + prefix: 'hocredux', + body: [ + "import React from 'react'", + "import { connect } from 'react-redux'", + "import PropTypes from 'prop-types'", + '', + 'export const mapStateToProps = state => ({})', + '', + 'export const mapDispatchToProps = {}', + '', + `export const ${Placeholders.FirstTab} = (WrappedComponent) => {`, + ' const hocComponent = ({ ...props }) => ', + '', + ' hocComponent.propTypes = {}', + '', + ' return hocComponent', + '}', + '', + `export default WrapperComponent => connect(mapStateToProps, mapDispatchToProps)(${Placeholders.FirstTab}(WrapperComponent))`, + '', + ], +}; + +const hocComponent: OthersSnippet = { + key: 'hocComponent', + prefix: 'hoc', + body: [ + "import React from 'react'", + "import PropTypes from 'prop-types'", + '', + 'export default (WrappedComponent) => {', + ' const hocComponent = ({ ...props }) => ', + '', + ' hocComponent.propTypes = {}', + '', + ' return hocComponent', + '}', + '', + ], +}; + +const typeofSnippet: OthersSnippet = { + key: 'typeofSnippet', + prefix: 'tpf', + body: [`typeof ${Placeholders.FirstTab}`], +}; + +export default [ + exportDefault, + exportDestructing, + exportAs, + exportNamedFunction, + exportDefaultFunction, + exportDefaultNamedFunction, + method, + propertyGet, + propertySet, + forEach, + forOf, + forIn, + anonymousFunction, + namedFunction, + destructingObject, + destructingArray, + setInterval, + setTimeOut, + promise, + destructProps, + destructState, + classConstructor, + emptyState, + componentDidMount, + shouldComponentUpdate, + componentDidUpdate, + componentWillUnmount, + getDerivedStateFromProps, + getSnapshotBeforeUpdate, + createContext, + createRef, + componentSetStateObject, + componentSetStateFunc, + componentProps, + componentState, + bindThis, + commentBigBlock, + hocComponentWithRedux, + hocComponent, + typeofSnippet, +]; diff --git a/src/sourceSnippets/propTypes.ts b/src/sourceSnippets/propTypes.ts new file mode 100644 index 0000000..3fd13cc --- /dev/null +++ b/src/sourceSnippets/propTypes.ts @@ -0,0 +1,291 @@ +import { SnippetMapping } from '../types'; + +type PropTypesMapping = { + propTypeAny: 'ptany'; + propTypeArray: 'pta'; + propTypeArrayOf: 'ptao'; + propTypeArrayOfRequired: 'ptaor'; + propTypeArrayRequired: 'ptar'; + propTypeBool: 'ptb'; + propTypeBoolRequired: 'ptbr'; + propTypeElement: 'ptel'; + propTypeElementRequired: 'ptelr'; + propTypeEnum: 'pte'; + propTypeEnumRequired: 'pter'; + propTypeExact: 'ptex'; + propTypeExactRequired: 'ptexr'; + propTypeFunc: 'ptf'; + propTypeFuncRequired: 'ptfr'; + propTypeInstanceOf: 'pti'; + propTypeInstanceOfRequired: 'ptir'; + propTypeNode: 'ptnd'; + propTypeNodeRequired: 'ptndr'; + propTypeNumber: 'ptn'; + propTypeNumberRequired: 'ptnr'; + propTypeObject: 'pto'; + propTypeObjectOf: 'ptoo'; + propTypeObjectOfRequired: 'ptoor'; + propTypeObjectRequired: 'ptor'; + propTypeOneOfType: 'ptet'; + propTypeOneOfTypeRequired: 'ptetr'; + propTypeShape: 'ptsh'; + propTypeShapeRequired: 'ptshr'; + propTypeString: 'pts'; + propTypeStringRequired: 'ptsr'; +}; + +export type PropTypesSnippet = SnippetMapping; + +const propTypeArray: PropTypesSnippet = { + key: 'propTypeArray', + prefix: 'pta', + body: ['PropTypes.array'], + description: 'Array prop type', +}; + +const propTypeArrayRequired: PropTypesSnippet = { + key: 'propTypeArrayRequired', + prefix: 'ptar', + body: ['PropTypes.array.isRequired'], + description: 'Array prop type required', +}; + +const propTypeBool: PropTypesSnippet = { + key: 'propTypeBool', + prefix: 'ptb', + body: ['PropTypes.bool'], + description: 'Bool prop type', +}; + +const propTypeBoolRequired: PropTypesSnippet = { + key: 'propTypeBoolRequired', + prefix: 'ptbr', + body: ['PropTypes.bool.isRequired'], + description: 'Bool prop type required', +}; + +const propTypeFunc: PropTypesSnippet = { + key: 'propTypeFunc', + prefix: 'ptf', + body: ['PropTypes.func'], + description: 'Func prop type', +}; + +const propTypeFuncRequired: PropTypesSnippet = { + key: 'propTypeFuncRequired', + prefix: 'ptfr', + body: ['PropTypes.func.isRequired'], + description: 'Func prop type required', +}; + +const propTypeNumber: PropTypesSnippet = { + key: 'propTypeNumber', + prefix: 'ptn', + body: ['PropTypes.number'], + description: 'Number prop type', +}; + +const propTypeNumberRequired: PropTypesSnippet = { + key: 'propTypeNumberRequired', + prefix: 'ptnr', + body: ['PropTypes.number.isRequired'], + description: 'Number prop type required', +}; + +const propTypeObject: PropTypesSnippet = { + key: 'propTypeObject', + prefix: 'pto', + body: ['PropTypes.object'], + description: 'Object prop type', +}; + +const propTypeObjectRequired: PropTypesSnippet = { + key: 'propTypeObjectRequired', + prefix: 'ptor', + body: ['PropTypes.object.isRequired'], + description: 'Object prop type required', +}; + +const propTypeString: PropTypesSnippet = { + key: 'propTypeString', + prefix: 'pts', + body: ['PropTypes.string'], + description: 'String prop type', +}; + +const propTypeStringRequired: PropTypesSnippet = { + key: 'propTypeStringRequired', + prefix: 'ptsr', + body: ['PropTypes.string.isRequired'], + description: 'String prop type required', +}; + +const propTypeNode: PropTypesSnippet = { + key: 'propTypeNode', + prefix: 'ptnd', + body: ['PropTypes.node'], + description: + 'Anything that can be rendered: numbers, strings, elements or an array', +}; + +const propTypeNodeRequired: PropTypesSnippet = { + key: 'propTypeNodeRequired', + prefix: 'ptndr', + body: ['PropTypes.node.isRequired'], + description: + 'Anything that can be rendered: numbers, strings, elements or an array required', +}; + +const propTypeElement: PropTypesSnippet = { + key: 'propTypeElement', + prefix: 'ptel', + body: ['PropTypes.element'], + description: 'React element prop type', +}; + +const propTypeElementRequired: PropTypesSnippet = { + key: 'propTypeElementRequired', + prefix: 'ptelr', + body: ['PropTypes.element.isRequired'], + description: 'React element prop type required', +}; + +const propTypeInstanceOf: PropTypesSnippet = { + key: 'propTypeInstanceOf', + prefix: 'pti', + body: ['PropTypes.instanceOf($0)'], + description: 'Is an instance of a class prop type', +}; + +const propTypeInstanceOfRequired: PropTypesSnippet = { + key: 'propTypeInstanceOfRequired', + prefix: 'ptir', + body: ['PropTypes.instanceOf($0).isRequired'], + description: 'Is an instance of a class prop type required', +}; + +const propTypeEnum: PropTypesSnippet = { + key: 'propTypeEnum', + prefix: 'pte', + body: ["PropTypes.oneOf(['$0'])"], + description: 'Prop type limited to specific values by treating it as an enum', +}; + +const propTypeEnumRequired: PropTypesSnippet = { + key: 'propTypeEnumRequired', + prefix: 'pter', + body: ["PropTypes.oneOf(['$0']).isRequired"], + description: + 'Prop type limited to specific values by treating it as an enum required', +}; + +const propTypeOneOfType: PropTypesSnippet = { + key: 'propTypeOneOfType', + prefix: 'ptet', + body: ['PropTypes.oneOfType([', ' $0', '])'], + description: 'An object that could be one of many types', +}; + +const propTypeOneOfTypeRequired: PropTypesSnippet = { + key: 'propTypeOneOfTypeRequired', + prefix: 'ptetr', + body: ['PropTypes.oneOfType([', ' $0', ']).isRequired'], + description: 'An object that could be one of many types required', +}; + +const propTypeArrayOf: PropTypesSnippet = { + key: 'propTypeArrayOf', + prefix: 'ptao', + body: ['PropTypes.arrayOf($0)'], + description: 'An array of a certain type', +}; + +const propTypeArrayOfRequired: PropTypesSnippet = { + key: 'propTypeArrayOfRequired', + prefix: 'ptaor', + body: ['PropTypes.arrayOf($0).isRequired'], + description: 'An array of a certain type required', +}; + +const propTypeObjectOf: PropTypesSnippet = { + key: 'propTypeObjectOf', + prefix: 'ptoo', + body: ['PropTypes.objectOf($0)'], + description: 'An object with property values of a certain type', +}; + +const propTypeObjectOfRequired: PropTypesSnippet = { + key: 'propTypeObjectOfRequired', + prefix: 'ptoor', + body: ['PropTypes.objectOf($0).isRequired'], + description: 'An object with property values of a certain type required', +}; + +const propTypeShape: PropTypesSnippet = { + key: 'propTypeShape', + prefix: 'ptsh', + body: ['PropTypes.shape({', ' $0', '})'], + description: 'An object taking on a particular shape', +}; + +const propTypeShapeRequired: PropTypesSnippet = { + key: 'propTypeShapeRequired', + prefix: 'ptshr', + body: ['PropTypes.shape({', ' $0', '}).isRequired'], + description: 'An object taking on a particular shape required', +}; + +const propTypeExact: PropTypesSnippet = { + key: 'propTypeExact', + prefix: 'ptex', + body: ['PropTypes.exact({', ' $0', '})'], + description: 'An object with warnings on extra properties', +}; + +const propTypeExactRequired: PropTypesSnippet = { + key: 'propTypeExactRequired', + prefix: 'ptexr', + body: ['PropTypes.exact({', ' $0', '}).isRequired'], + description: 'An object with warnings on extra properties required', +}; + +const propTypeAny: PropTypesSnippet = { + key: 'propTypeAny', + prefix: 'ptany', + body: ['PropTypes.any'], + description: 'Any prop type', +}; + +export default [ + propTypeArray, + propTypeArrayRequired, + propTypeBool, + propTypeBoolRequired, + propTypeFunc, + propTypeFuncRequired, + propTypeNumber, + propTypeNumberRequired, + propTypeObject, + propTypeObjectRequired, + propTypeString, + propTypeStringRequired, + propTypeNode, + propTypeNodeRequired, + propTypeElement, + propTypeElementRequired, + propTypeInstanceOf, + propTypeInstanceOfRequired, + propTypeEnum, + propTypeEnumRequired, + propTypeOneOfType, + propTypeOneOfTypeRequired, + propTypeArrayOf, + propTypeArrayOfRequired, + propTypeObjectOf, + propTypeObjectOfRequired, + propTypeShape, + propTypeShapeRequired, + propTypeExact, + propTypeExactRequired, + propTypeAny, +]; diff --git a/src/sourceSnippets/reactNative.ts b/src/sourceSnippets/reactNative.ts new file mode 100644 index 0000000..0a06d6c --- /dev/null +++ b/src/sourceSnippets/reactNative.ts @@ -0,0 +1,196 @@ +import { Placeholders, SnippetMapping } from '../types'; + +import { + exportDefault, + react, + reactComponent, + reactPureComponent, +} from './sharedSnippets'; + +type ReactNativeMapping = { + reactNativeImport: 'imrn'; + reactNativeStyles: 'rnstyle'; + reactNativeComponent: 'rnc'; + reactNativeComponentWithStyles: 'rncs'; + reactNativeComponentExport: 'rnce'; + reactNativePureComponent: 'rnpc'; + reactNativePureComponentExport: 'rnpce'; + reactNativeFunctionalExportComponent: 'rnfe'; + reactNativeFunctionalExportComponentWithStyles: 'rnfes'; + reactNativeFunctionalComponent: 'rnf'; + reactNativeFunctionalComponentWithStyles: 'rnfs'; +}; + +export type ReactNativeSnippet = SnippetMapping; + +const reactNativeStylesSnippet = ['const styles = StyleSheet.create({})']; +const reactNativeComponentReturn = [ + ' render() {', + ' return (', + ' ', + ` ${Placeholders.FirstTab}`, + ' ', + ' )', + ' }', +]; + +const reactNativeReturn = [ + ' return (', + ' ', + ` ${Placeholders.FirstTab}`, + ' ', + ' )', +]; + +const reactNativeImport: ReactNativeSnippet = { + key: 'reactNativeImport', + prefix: 'imrn', + body: [`import { ${Placeholders.FirstTab} } from 'react-native'`], +}; + +const reactNativeStyles: ReactNativeSnippet = { + key: 'reactNativeStyles', + prefix: 'rnstyle', + body: [`const styles = StyleSheet.create({${Placeholders.FirstTab}})`], +}; + +const reactNativeComponent: ReactNativeSnippet = { + key: 'reactNativeComponent', + prefix: 'rnc', + body: [ + "import { Text, View } from 'react-native'", + ...reactComponent, + '', + `export default class ${Placeholders.FileName} extends Component {`, + ...reactNativeComponentReturn, + '}', + ], +}; + +const reactNativeComponentWithStyles: ReactNativeSnippet = { + key: 'reactNativeComponentWithStyles', + prefix: 'rncs', + body: [ + "import { Text, StyleSheet, View } from 'react-native'", + ...reactComponent, + '', + `export default class ${Placeholders.FileName} extends Component {`, + ...reactNativeComponentReturn, + '}', + '', + ...reactNativeStylesSnippet, + ], +}; + +const reactNativeComponentExport: ReactNativeSnippet = { + key: 'reactNativeComponentExport', + prefix: 'rnce', + body: [ + "import { Text, View } from 'react-native'", + ...reactComponent, + '', + `export class ${Placeholders.FileName} extends Component {`, + ...reactNativeComponentReturn, + '}', + ...exportDefault, + ], +}; + +const reactNativePureComponent: ReactNativeSnippet = { + key: 'reactNativePureComponent', + prefix: 'rnpc', + body: [ + "import { Text, View } from 'react-native'", + ...reactPureComponent, + '', + `export default class ${Placeholders.FileName} extends PureComponent {`, + ...reactNativeComponentReturn, + '}', + ], +}; + +const reactNativePureComponentExport: ReactNativeSnippet = { + key: 'reactNativePureComponentExport', + prefix: 'rnpce', + body: [ + "import { Text, View } from 'react-native'", + ...reactPureComponent, + '', + `export class ${Placeholders.FileName} extends PureComponent {`, + ...reactNativeComponentReturn, + '}', + ...exportDefault, + ], +}; + +const reactNativeFunctionalExportComponent: ReactNativeSnippet = { + key: 'reactNativeFunctionalExportComponent', + prefix: 'rnfe', + body: [ + "import { View, Text } from 'react-native'", + ...react, + '', + `const ${Placeholders.FileName} = () => {`, + ...reactNativeReturn, + '}', + ...exportDefault, + ], +}; + +const reactNativeFunctionalExportComponentWithStyles: ReactNativeSnippet = { + key: 'reactNativeFunctionalExportComponentWithStyles', + prefix: 'rnfes', + body: [ + "import { StyleSheet, Text, View } from 'react-native'", + ...react, + '', + `const ${Placeholders.FileName} = () => {`, + ...reactNativeReturn, + '}', + ...exportDefault, + '', + ...reactNativeStylesSnippet, + ], +}; + +const reactNativeFunctionalComponent: ReactNativeSnippet = { + key: 'reactNativeFunctionalComponent', + prefix: 'rnf', + body: [ + "import { View, Text } from 'react-native'", + ...react, + '', + `export default function ${Placeholders.FileName}() {`, + ...reactNativeReturn, + '}', + ], +}; + +const reactNativeFunctionalComponentWithStyles: ReactNativeSnippet = { + key: 'reactNativeFunctionalComponentWithStyles', + prefix: 'rnfs', + body: [ + "import { StyleSheet, Text, View } from 'react-native'", + ...react, + '', + `export default function ${Placeholders.FileName}() {`, + ...reactNativeReturn, + '}', + '', + ...reactNativeStylesSnippet, + ], +}; + +export default [ + reactNativeComponent, + reactNativeComponentExport, + reactNativeComponentWithStyles, + reactNativeFunctionalComponent, + reactNativeFunctionalComponentWithStyles, + reactNativeFunctionalExportComponent, + reactNativeFunctionalExportComponentWithStyles, + reactNativeImport, + reactNativePureComponent, + reactNativePureComponentExport, + reactNativeStyles, +]; diff --git a/src/sourceSnippets/redux.ts b/src/sourceSnippets/redux.ts new file mode 100644 index 0000000..0315fc9 --- /dev/null +++ b/src/sourceSnippets/redux.ts @@ -0,0 +1,109 @@ +import { Placeholders, SnippetMapping } from '../types'; + +type ReduxMapping = { + importReduxConnect: 'redux'; + reduxAction: 'rxaction'; + reduxConst: 'rxconst'; + reduxReducer: 'rxreducer'; + reduxSelector: 'rxselect'; + reduxSlice: 'rxslice'; + mappingToProps: 'reduxmap'; +}; + +export type ReduxSnippet = SnippetMapping; + +const importReduxConnect: ReduxSnippet = { + key: 'importReduxConnect', + prefix: 'redux', + body: ["import { connect } from 'react-redux'"], +}; + +const reduxAction: ReduxSnippet = { + key: 'reduxAction', + prefix: 'rxaction', + body: [ + `export const ${Placeholders.FirstTab} = (payload) => ({`, + ` type: ${Placeholders.SecondTab},`, + ' payload', + '})', + '', + ], +}; + +const reduxConst: ReduxSnippet = { + key: 'reduxConst', + prefix: 'rxconst', + body: [`export const ${Placeholders.FirstTab} = '${Placeholders.FirstTab}'`], +}; + +const reduxReducer: ReduxSnippet = { + key: 'reduxReducer', + prefix: 'rxreducer', + body: [ + 'const initialState = {}', + '', + 'export default (state = initialState, { type, payload }) => {', + ' switch (type) {', + '', + ` case ${Placeholders.FirstTab}:`, + ' return { ...state, ...payload }', + '', + ' default:', + ' return state', + ' }', + '}', + '', + ], +}; + +const reduxSelector: ReduxSnippet = { + key: 'reduxSelector', + prefix: 'rxselect', + body: [ + "import { createSelector } from 'reselect'", + '', + `export const ${Placeholders.FirstTab} = state => state.${Placeholders.SecondTab}`, + ], +}; + +const reduxSlice: ReduxSnippet = { + key: 'reduxSlice', + prefix: 'rxslice', + body: [ + "import { createSlice } from '@reduxjs/toolkit'", + '', + 'const initialState = {', + '', + '}', + '', + `const ${Placeholders.FileName} = createSlice({`, + ` name: ${Placeholders.SecondTab},`, + ' initialState,', + ' reducers: {}', + '});', + '', + `export const {} = ${Placeholders.FileName}.actions`, + '', + `export default ${Placeholders.FileName}.reducer`, + ], +}; + +const mappingToProps: ReduxSnippet = { + key: 'mappingToProps', + prefix: 'reduxmap', + body: [ + 'const mapStateToProps = (state) => ({})', + '', + 'const mapDispatchToProps = {}', + ], +}; + +export default [ + importReduxConnect, + reduxAction, + reduxConst, + reduxReducer, + reduxSelector, + reduxSlice, + mappingToProps, +]; diff --git a/src/sourceSnippets/sharedSnippets.ts b/src/sourceSnippets/sharedSnippets.ts new file mode 100644 index 0000000..6a199ac --- /dev/null +++ b/src/sourceSnippets/sharedSnippets.ts @@ -0,0 +1,55 @@ +import { Placeholders } from '../types'; + +export const reactComponent = ["import React, { Component } from 'react'"]; +export const react = ["import React from 'react'"]; +export const reactPureComponent = [ + "import React, { PureComponent } from 'react'", +]; +export const reactPropTypes = [ + "import React from 'react'", + "import PropTypes from 'prop-types'", +]; + +export const reactWithReduxConnect = [ + "import React from 'react'", + "import { connect } from 'react-redux'", +]; + +export const reactComponentWithReduxConnect = [ + "import React, { Component } from 'react'", + "import { connect } from 'react-redux'", +]; + +export const reactWithMemo = ["import React, { memo } from 'react'"]; + +export const reduxComponentExport = [ + '', + 'const mapStateToProps = (state) => ({})', + '', + 'const mapDispatchToProps = {}', + '', + `export default connect(mapStateToProps, mapDispatchToProps)(${Placeholders.FileName})`, +]; + +export const innerComponent = [ + ' return (', + `
${Placeholders.FirstTab}
`, + ' )', +]; + +export const innerComponentReturn = [ + ' render() {', + ' return (', + `
${Placeholders.FirstTab}
`, + ' )', + ' }', +]; + +export const exportDefault = ['', `export default ${Placeholders.FileName}`]; + +export const propsTypeInterface = [Placeholders.TypeProps, '']; +export const stateTypeInterface = [Placeholders.TypeState, '']; +export const propsStateInterface = [ + ...propsTypeInterface, + ...stateTypeInterface, +]; diff --git a/src/sourceSnippets/tests.ts b/src/sourceSnippets/tests.ts new file mode 100644 index 0000000..73ebadb --- /dev/null +++ b/src/sourceSnippets/tests.ts @@ -0,0 +1,159 @@ +import { Placeholders, SnippetMapping } from '../types'; + +type TestMapping = { + describeBlock: 'desc'; + itAsyncBlock: 'tita'; + itBlock: 'tit'; + setupReactComponentTestWithRedux: 'srtest'; + setupReactNativeTest: 'sntest'; + setupReactNativeTestWithRedux: 'snrtest'; + setupReactTest: 'stest'; + testAsyncBlock: 'testa'; + testBlock: 'test'; +}; + +export type TestsSnippet = SnippetMapping; + +const describeBlock: TestsSnippet = { + key: 'describeBlock', + prefix: 'desc', + body: [ + `describe('${Placeholders.FirstTab}', () => { ${Placeholders.SecondTab} })`, + ], + description: 'Testing `describe` block', +}; +const testBlock: TestsSnippet = { + key: 'testBlock', + prefix: 'test', + body: [ + `test('should ${Placeholders.FirstTab}', () => { ${Placeholders.SecondTab} })`, + ], + description: 'Testing `test` block', +}; +const testAsyncBlock: TestsSnippet = { + key: 'testAsyncBlock', + prefix: 'testa', + body: [ + `test('should ${Placeholders.FirstTab}', async () => { ${Placeholders.SecondTab} })`, + ], + description: 'Testing `asynchronous test` block', +}; +const itBlock: TestsSnippet = { + key: 'itBlock', + prefix: 'tit', + body: [ + `it('should ${Placeholders.FirstTab}', () => { ${Placeholders.SecondTab} })`, + ], + description: 'Testing `it` block', +}; +const itAsyncBlock: TestsSnippet = { + key: 'itAsyncBlock', + prefix: 'tita', + body: [ + `it('should ${Placeholders.FirstTab}', async () => { ${Placeholders.SecondTab} })`, + ], + description: 'Testing asynchronous `it` block', +}; +const setupReactTest: TestsSnippet = { + key: 'setupReactTest', + prefix: 'stest', + body: [ + "import React from 'react'", + "import renderer from 'react-test-renderer'", + '', + `import { ${Placeholders.FileName} } from '../${Placeholders.FileName}'`, + '', + `describe('<${Placeholders.FileName} />', () => {`, + ' const defaultProps = {}', + ` const wrapper = renderer.create(<${Placeholders.FileName} {...defaultProps} />)`, + '', + " test('render', () => {", + ' expect(wrapper).toMatchSnapshot()', + ' })', + '})', + ], +}; +const setupReactNativeTest: TestsSnippet = { + key: 'setupReactNativeTest', + prefix: 'sntest', + body: [ + "import 'react-native'", + "import React from 'react'", + "import renderer from 'react-test-renderer'", + '', + `import ${Placeholders.FileName} from '../${Placeholders.FileName}'`, + '', + `describe('<${Placeholders.FileName} />', () => {`, + ' const defaultProps = {}', + ` const wrapper = renderer.create(<${Placeholders.FileName} {...defaultProps} />)`, + '', + " test('render', () => {", + ' expect(wrapper).toMatchSnapshot()', + ' })', + '})', + ], +}; +const setupReactComponentTestWithRedux: TestsSnippet = { + key: 'setupReactComponentTestWithRedux', + prefix: 'srtest', + body: [ + "import React from 'react'", + "import renderer from 'react-test-renderer'", + "import { Provider } from 'react-redux'", + '', + "import store from '~/store'", + `import { ${Placeholders.FileName} } from '../${Placeholders.FileName}'`, + '', + `describe('<${Placeholders.FileName} />', () => {`, + ' const defaultProps = {}', + ' const wrapper = renderer.create(', + ' ', + ` <${Placeholders.FileName} {...defaultProps} />`, + ' ,', + ' )', + '', + " test('render', () => {", + ' expect(wrapper).toMatchSnapshot()', + ' })', + '})', + ], + description: 'Create test component', +}; +const setupReactNativeTestWithRedux: TestsSnippet = { + key: 'setupReactNativeTestWithRedux', + prefix: 'snrtest', + body: [ + "import 'react-native'", + "import React from 'react'", + "import renderer from 'react-test-renderer'", + "import { Provider } from 'react-redux'", + '', + "import store from '~/store'", + `import ${Placeholders.FileName} from '../${Placeholders.FileName}'`, + '', + `describe('<${Placeholders.FileName} />', () => {`, + ' const defaultProps = {}', + ' const wrapper = renderer.create(', + ' ', + ` <${Placeholders.FileName} {...defaultProps} />`, + ' ,', + ' )', + '', + " test('render', () => {", + ' expect(wrapper).toMatchSnapshot()', + ' })', + '})', + ], +}; + +export default [ + describeBlock, + itAsyncBlock, + itBlock, + setupReactComponentTestWithRedux, + setupReactNativeTest, + setupReactNativeTestWithRedux, + setupReactTest, + testAsyncBlock, + testBlock, +]; diff --git a/src/sourceSnippets/typescript.ts b/src/sourceSnippets/typescript.ts new file mode 100644 index 0000000..d024a0c --- /dev/null +++ b/src/sourceSnippets/typescript.ts @@ -0,0 +1,253 @@ +import { Placeholders, SnippetMapping } from '../types'; + +import { + exportDefault, + innerComponent, + innerComponentReturn, + propsStateInterface, + propsTypeInterface, + react, + reactComponent, + reactPureComponent, + reduxComponentExport, +} from './sharedSnippets'; + +type TypescriptMappings = { + exportInterface: 'expint'; + exportType: 'exptp'; + typescriptReactArrowFunctionComponent: 'tsrafc'; + typescriptReactArrowFunctionExportComponent: 'tsrafce'; + typescriptReactClassComponent: 'tsrcc'; + typescriptReactClassComponentRedux: 'tsrcredux'; + typescriptReactClassExportComponent: 'tsrce'; + typescriptReactClassExportPureComponent: 'tsrpce'; + typescriptReactClassPureComponent: 'tsrpc'; + typescriptReactFunctionalComponent: 'tsrfc'; + typescriptReactFunctionalExportComponent: 'tsrfce'; + typescriptReactNativeArrowFunctionComponent: 'tsrnf'; + typescriptReactNativeArrowFunctionComponentWithStyles: 'tsrnfs'; +}; + +export type TypescriptSnippet = SnippetMapping; + +const exportType: TypescriptSnippet = { + body: [`export type ${Placeholders.FirstTab} = {${Placeholders.SecondTab}}`], + key: 'exportType', + prefix: 'exptp', +}; + +const exportInterface: TypescriptSnippet = { + key: 'exportInterface', + prefix: 'expint', + body: [ + `export interface ${Placeholders.FirstTab} {${Placeholders.SecondTab}}`, + ], +}; + +const typescriptReactClassComponent: TypescriptSnippet = { + key: 'typescriptReactClassComponent', + prefix: 'tsrcc', + description: + 'Creates a React component class with ES7 module system and TypeScript interfaces', + body: [ + ...reactComponent, + '', + ...propsStateInterface, + `export default class ${Placeholders.FileName} extends Component {`, + ' state = {}', + '', + ...innerComponentReturn, + '}', + ], +}; + +const typescriptReactClassExportComponent: TypescriptSnippet = { + key: 'typescriptReactClassExportComponent', + prefix: 'tsrce', + body: [ + ...reactComponent, + '', + ...propsStateInterface, + `class ${Placeholders.FileName} extends Component {`, + ' state = {}', + '', + ...innerComponentReturn, + '}', + ...exportDefault, + ], + description: + 'Creates a React component class with ES7 module system and TypeScript interfaces', +}; + +const typescriptReactFunctionalExportComponent: TypescriptSnippet = { + key: 'typescriptReactFunctionalExportComponent', + prefix: 'tsrfce', + body: [ + ...react, + '', + ...propsTypeInterface, + `function ${Placeholders.FileName}({}: Props) {`, + ...innerComponent, + '}', + ...exportDefault, + ], + description: + 'Creates a React Functional Component with ES7 module system and TypeScript interface', +}; + +const typescriptReactFunctionalComponent: TypescriptSnippet = { + key: 'typescriptReactFunctionalComponent', + prefix: 'tsrfc', + body: [ + ...react, + '', + ...propsTypeInterface, + `export default function ${Placeholders.FileName}({}: Props) {`, + ...innerComponent, + '}', + ], + description: + 'Creates a React Functional Component with ES7 module system and TypeScript interface', +}; + +const typescriptReactArrowFunctionExportComponent: TypescriptSnippet = { + key: 'typescriptReactArrowFunctionExportComponent', + prefix: 'tsrafce', + body: [ + ...react, + '', + ...propsTypeInterface, + `const ${Placeholders.FileName} = (props: Props) => {`, + ...innerComponent, + '}', + ...exportDefault, + ], + description: + 'Creates a React Arrow Function Component with ES7 module system and TypeScript interface', +}; + +const typescriptReactArrowFunctionComponent: TypescriptSnippet = { + key: 'typescriptReactArrowFunctionComponent', + prefix: 'tsrafc', + body: [ + ...react, + '', + ...propsTypeInterface, + `const ${Placeholders.FileName} = (props: Props) => {`, + ...innerComponent, + '}', + ], + description: + 'Creates a React Arrow Function Component with ES7 module system and TypeScript interface', +}; + +const typescriptReactClassPureComponent: TypescriptSnippet = { + key: 'typescriptReactClassPureComponent', + prefix: 'tsrpc', + body: [ + ...reactPureComponent, + '', + ...propsTypeInterface, + `export default class ${Placeholders.FileName} extends PureComponent {`, + ...innerComponentReturn, + '}', + ], + description: + 'Creates a React pure component class with ES7 module system and TypeScript interface', +}; + +const typescriptReactClassExportPureComponent: TypescriptSnippet = { + key: 'typescriptReactClassExportPureComponent', + prefix: 'tsrpce', + body: [ + ...reactPureComponent, + '', + ...propsTypeInterface, + `class ${Placeholders.FileName} extends PureComponent {`, + ...innerComponentReturn, + '}', + ...exportDefault, + ], + description: + 'Creates a React pure component class with ES7 module system and TypeScript interface', +}; + +const typescriptReactClassComponentRedux: TypescriptSnippet = { + key: 'typescriptReactClassComponentRedux', + prefix: 'tsrcredux', + body: [ + "import { connect } from 'react-redux'", + ...reactComponent, + '', + ...propsStateInterface, + `export class ${Placeholders.FileName} extends Component {`, + ' state = {}', + '', + ...innerComponentReturn, + '}', + ...reduxComponentExport, + ], + description: + 'Creates a React component class with connected redux and ES7 module system and TypeScript interfaces', +}; + +const typescriptReactNativeArrowFunctionComponent: TypescriptSnippet = { + key: 'typescriptReactNativeArrowFunctionComponent', + prefix: 'tsrnf', + body: [ + "import { View, Text } from 'react-native'", + ...react, + '', + ...propsTypeInterface, + `const ${Placeholders.FileName} = (props: Props) => {`, + ' return (', + ' ', + ` ${Placeholders.FirstTab}`, + ' ', + ' )', + '}', + ...exportDefault, + ], + description: + 'Creates a React Native Arrow Function Component with ES7 module system in TypeScript', +}; + +const typescriptReactNativeArrowFunctionComponentWithStyles: TypescriptSnippet = + { + key: 'typescriptReactNativeArrowFunctionComponentWithStyles', + prefix: 'tsrnfs', + body: [ + "import { StyleSheet, Text, View } from 'react-native'", + ...react, + '', + ...propsTypeInterface, + `const ${Placeholders.FileName} = (props: Props) => {`, + ' return (', + ' ', + ` ${Placeholders.FirstTab}`, + ' ', + ' )', + '}', + ...exportDefault, + '', + 'const styles = StyleSheet.create({})', + ], + description: + 'Creates a React Native Arrow Function Component with ES7 module system, TypeScript interface and StyleSheet', + }; + +export default [ + exportType, + exportInterface, + typescriptReactClassComponent, + typescriptReactClassExportComponent, + typescriptReactFunctionalExportComponent, + typescriptReactFunctionalComponent, + typescriptReactArrowFunctionExportComponent, + typescriptReactArrowFunctionComponent, + typescriptReactClassPureComponent, + typescriptReactClassExportPureComponent, + typescriptReactClassComponentRedux, + typescriptReactNativeArrowFunctionComponent, + typescriptReactNativeArrowFunctionComponentWithStyles, +]; diff --git a/src/test.ts b/src/test.ts new file mode 100644 index 0000000..49ebdc1 --- /dev/null +++ b/src/test.ts @@ -0,0 +1,21 @@ + +import { writeFile } from 'fs'; + +const generateSnippets = () => + new Promise((resolve) => { + const jsonSnippets = `{}`; + writeFile( + __dirname + '/../snippets/generated.json', + jsonSnippets, + (error) => { + if (error) { + console.error(error); + } + return resolve(true); + }, + ); + }); + +generateSnippets() + +export default generateSnippets; diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..19fa619 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,28 @@ +export type SnippetMapping = { + key: keyof T; + prefix: T[keyof T]; + body: string[]; + description?: string; +}; + +export const Placeholders = { + FileName: 'file', + FirstTab: 'first', + SecondTab: 'second', + ThirdTab: 'third', + Capitalize: 'capitalize', + TypeProps: 'typeProps', + TypeState: 'typeState', +} as const; + +export const Mappings = { + FileName: '${1:${TM_FILENAME_BASE}}', + FirstTab: '${1:first}', + SecondTab: '${2:second}', + ThirdTab: '${3:third}', + Capitalize: '${1/(.*)/${1:/capitalize}/}', + TypeProps: 'type Props = {}', + TypeState: 'type State = {}', + InterfaceProps: 'interface Props {}', + InterfaceState: 'interface State {}', +} as const; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..c1aa99d --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "allowJs": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "module": "amd", + "moduleResolution": "Node", + "noEmit": true, + "noImplicitAny": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "skipDefaultLibCheck": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "strictNullChecks": true, + "target": "ESNext" + }, + "exclude": ["node_modules", "jest", "**/__tests__/*"], + "compileOnSave": false +}