Skip to content

Commit acf16c0

Browse files
committed
feat(add): add typescript
1 parent cee370c commit acf16c0

File tree

5 files changed

+344
-0
lines changed

5 files changed

+344
-0
lines changed

add/add_typescript_node.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package add
2+
3+
import (
4+
"bytes"
5+
6+
"github.com/pkg/errors"
7+
"github.com/pot-code/web-cli/core"
8+
"github.com/pot-code/web-cli/templates"
9+
"github.com/pot-code/web-cli/util"
10+
log "github.com/sirupsen/logrus"
11+
)
12+
13+
type AddTypescriptToNode struct {
14+
recipe *util.GenerationRecipe
15+
gen core.Generator
16+
}
17+
18+
var _ core.Executor = AddTypescriptToNode{}
19+
20+
func NewAddTypescriptToNode() *AddTypescriptToNode {
21+
recipe := util.NewGenerationRecipe("",
22+
&util.GenerationMaterial{
23+
Path: "./.eslintrc.js",
24+
Provider: func() []byte {
25+
var buf bytes.Buffer
26+
27+
templates.WriteNodeEslintrc(&buf)
28+
return buf.Bytes()
29+
},
30+
},
31+
&util.GenerationMaterial{
32+
Path: "./tsconfig.json",
33+
Provider: func() []byte {
34+
var buf bytes.Buffer
35+
36+
templates.WriteNodeTsConfig(&buf)
37+
return buf.Bytes()
38+
},
39+
},
40+
)
41+
return &AddTypescriptToNode{recipe: recipe}
42+
}
43+
44+
func (atn AddTypescriptToNode) Run() error {
45+
cmd := core.NewCmdExecutor("npm", "i", "-D",
46+
"typescript",
47+
"eslint",
48+
"@typescript-eslint/eslint-plugin",
49+
"eslint-plugin-prettier",
50+
"@typescript-eslint/parser",
51+
"eslint-config-prettier",
52+
"eslint-plugin-import",
53+
)
54+
55+
if err := cmd.Run(); err != nil {
56+
return errors.Wrap(err, "failed to install dependencies")
57+
}
58+
59+
log.Debugf("generation tree:\n%s", atn.recipe.GetGenerationTree())
60+
gen := atn.recipe.MakeGenerator()
61+
atn.gen = gen
62+
return errors.Wrap(gen.Run(), "failed to generate typescript config")
63+
}

add/add_typescript_react.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package add
2+
3+
import (
4+
"bytes"
5+
6+
"github.com/pkg/errors"
7+
"github.com/pot-code/web-cli/core"
8+
"github.com/pot-code/web-cli/templates"
9+
"github.com/pot-code/web-cli/util"
10+
log "github.com/sirupsen/logrus"
11+
)
12+
13+
type AddTypescriptToReact struct {
14+
recipe *util.GenerationRecipe
15+
gen core.Generator
16+
}
17+
18+
var _ core.Executor = AddTypescriptToReact{}
19+
20+
func NewAddTypescriptToReact() *AddTypescriptToReact {
21+
recipe := util.NewGenerationRecipe("",
22+
&util.GenerationMaterial{
23+
Path: "./.eslintrc.js",
24+
Provider: func() []byte {
25+
var buf bytes.Buffer
26+
27+
templates.WriteReactEslintrc(&buf)
28+
return buf.Bytes()
29+
},
30+
},
31+
&util.GenerationMaterial{
32+
Path: "./tsconfig.json",
33+
Provider: func() []byte {
34+
var buf bytes.Buffer
35+
36+
templates.WriteReactTsConfig(&buf)
37+
return buf.Bytes()
38+
},
39+
},
40+
)
41+
return &AddTypescriptToReact{recipe: recipe}
42+
}
43+
44+
func (atn AddTypescriptToReact) Run() error {
45+
cmd := core.NewCmdExecutor("npm", "i", "-D",
46+
"@typescript-eslint/eslint-plugin",
47+
"@typescript-eslint/parser",
48+
"eslint",
49+
"eslint-config-airbnb",
50+
"eslint-config-prettier",
51+
"eslint-import-resolver-typescript",
52+
"eslint-plugin-import",
53+
"eslint-plugin-jsx-a11y",
54+
"eslint-plugin-prettier",
55+
"eslint-plugin-react",
56+
"eslint-plugin-react-hooks",
57+
"prettier",
58+
"prettier-eslint",
59+
"typescript",
60+
)
61+
62+
if err := cmd.Run(); err != nil {
63+
return errors.Wrap(err, "failed to install dependencies")
64+
}
65+
66+
log.Debugf("generation tree:\n%s", atn.recipe.GetGenerationTree())
67+
gen := atn.recipe.MakeGenerator()
68+
atn.gen = gen
69+
return errors.Wrap(gen.Run(), "failed to generate typescript config")
70+
}

cmd/add.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package cmd
2+
3+
import "github.com/urfave/cli/v2"
4+
5+
var AddCmd = &cli.Command{
6+
Name: "add",
7+
Usage: "add framework support",
8+
Subcommands: []*cli.Command{
9+
addTypescriptCmd,
10+
},
11+
}

cmd/add_typescript.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
"github.com/pot-code/web-cli/add"
8+
"github.com/pot-code/web-cli/util"
9+
"github.com/urfave/cli/v2"
10+
)
11+
12+
const CmdTypescriptName = "typescript"
13+
14+
type AddTypescriptConfig struct {
15+
Target string
16+
}
17+
18+
var addTypescriptCmd = &cli.Command{
19+
Name: CmdTypescriptName,
20+
Usage: "add typescript support",
21+
Aliases: []string{"ts"},
22+
Flags: []cli.Flag{
23+
&cli.StringFlag{
24+
Name: "target",
25+
Aliases: []string{"T"},
26+
Usage: "project target (node/react)",
27+
Value: "node",
28+
},
29+
},
30+
Action: func(c *cli.Context) error {
31+
config, err := getAddTypescriptConfig(c)
32+
if err != nil {
33+
if _, ok := err.(*util.CommandError); ok {
34+
cli.ShowCommandHelp(c, CmdTypescriptName)
35+
}
36+
return err
37+
}
38+
39+
if config.Target == "node" {
40+
cmd := add.NewAddTypescriptToNode()
41+
return cmd.Run()
42+
}
43+
cmd := add.NewAddTypescriptToReact()
44+
return cmd.Run()
45+
},
46+
}
47+
48+
func getAddTypescriptConfig(c *cli.Context) (*AddTypescriptConfig, error) {
49+
config := &AddTypescriptConfig{}
50+
target := strings.ToLower(c.String("target"))
51+
if target == "" {
52+
return nil, util.NewCommandError(CmdTypescriptName, fmt.Errorf("target is empty"))
53+
} else if target == "node" || target == "react" {
54+
config.Target = target
55+
} else {
56+
return nil, util.NewCommandError(CmdTypescriptName, fmt.Errorf("unsupported target '%s'", target))
57+
}
58+
return config, nil
59+
}

templates/add_typescript.qtpl

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
{% func NodeEslintrc() %}
2+
module.exports = {
3+
parser: '@typescript-eslint/parser',
4+
parserOptions: {
5+
project: 'tsconfig.base.json',
6+
sourceType: 'module',
7+
},
8+
plugins: ['@typescript-eslint/eslint-plugin', 'import'],
9+
extends: ['plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'],
10+
root: true,
11+
env: {
12+
node: true,
13+
jest: true,
14+
},
15+
ignorePatterns: ['.eslintrc.js'],
16+
rules: {
17+
'@typescript-eslint/interface-name-prefix': 'off',
18+
'@typescript-eslint/explicit-function-return-type': 'off',
19+
'@typescript-eslint/explicit-module-boundary-types': 'off',
20+
'@typescript-eslint/no-explicit-any': 'off',
21+
'@typescript-eslint/no-empty-function': 'off',
22+
'import/order': [
23+
'error',
24+
{
25+
groups: ['builtin', 'external', 'internal', 'sibling', 'parent'],
26+
'newlines-between': 'always-and-inside-groups',
27+
},
28+
],
29+
},
30+
};
31+
{% endfunc %}
32+
33+
{% func ReactEslintrc() %}
34+
module.exports = {
35+
env: {
36+
browser: true,
37+
es2021: true
38+
},
39+
extends: ['airbnb', 'plugin:react/recommended', 'plugin:react-hooks/recommended', 'prettier'],
40+
parser: '@typescript-eslint/parser',
41+
ignorePatterns: ['.eslintrc.js'],
42+
parserOptions: {
43+
ecmaFeatures: {
44+
jsx: true
45+
},
46+
ecmaVersion: 12,
47+
sourceType: 'module'
48+
},
49+
plugins: ['react', '@typescript-eslint', 'import'],
50+
rules: {
51+
// built-in
52+
'no-unused-vars': 'off',
53+
'no-use-before-define': 'off',
54+
55+
// react
56+
'react/jsx-filename-extension': [1, { extensions: ['.tsx', '.jsx', '.js'] }],
57+
'react/react-in-jsx-scope': 'off',
58+
'react/jsx-props-no-spreading': 'off',
59+
60+
// import
61+
'import/extensions': 'off',
62+
'import/order': [
63+
'error',
64+
{
65+
groups: ['builtin', 'external', 'internal', 'parent', 'sibling'],
66+
'newlines-between': 'always',
67+
pathGroups: [
68+
{
69+
pattern: 'react',
70+
group: 'builtin'
71+
},
72+
{
73+
pattern: 'next/**',
74+
group: 'builtin'
75+
}
76+
],
77+
pathGroupsExcludedImportTypes: ['builtin', 'object']
78+
}
79+
]
80+
},
81+
settings: {
82+
'import/parsers': {
83+
'@typescript-eslint/parser': ['.ts', '.tsx']
84+
},
85+
'import/resolver': {
86+
typescript: {
87+
project: 'tsconfig.json'
88+
}
89+
}
90+
}
91+
};
92+
{% endfunc %}
93+
94+
{% func ReactTsConfig() %}
95+
{
96+
"compilerOptions": {
97+
"target": "es5",
98+
"lib": [
99+
"dom",
100+
"dom.iterable",
101+
"esnext"
102+
],
103+
"allowJs": true,
104+
"skipLibCheck": true,
105+
"strict": false,
106+
"forceConsistentCasingInFileNames": true,
107+
"noEmit": true,
108+
"esModuleInterop": true,
109+
"module": "esnext",
110+
"moduleResolution": "node",
111+
"resolveJsonModule": true,
112+
"isolatedModules": true,
113+
"jsx": "preserve"
114+
},
115+
"include": [
116+
"next-env.d.ts",
117+
"**/*.ts",
118+
"**/*.tsx"
119+
],
120+
"exclude": [
121+
"node_modules"
122+
]
123+
}
124+
{% endfunc %}
125+
126+
{% func NodeTsConfig() %}
127+
{
128+
"compilerOptions": {
129+
"module": "commonjs",
130+
"declaration": true,
131+
"removeComments": true,
132+
"allowSyntheticDefaultImports": true,
133+
"target": "es2017",
134+
"sourceMap": true,
135+
"outDir": "./dist",
136+
"baseUrl": "./",
137+
"incremental": true,
138+
"esModuleInterop": true,
139+
}
140+
}
141+
{% endfunc %}

0 commit comments

Comments
 (0)