@spark-ui/cli-utils 1.3.1 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/bin/core/Logger.mjs +19 -0
  3. package/bin/core/System.mjs +45 -0
  4. package/bin/core/index.mjs +2 -0
  5. package/bin/generators/Generator.mjs +5 -0
  6. package/bin/generators/TemplateGenerator.mjs +83 -0
  7. package/bin/generators/index.mjs +2 -0
  8. package/bin/spark-generate.mjs +35 -120
  9. package/bin/spark-setup-theme.mjs +6 -4
  10. package/bin/validators/DescriptionValidator.mjs +19 -0
  11. package/bin/validators/NameValidator.mjs +25 -0
  12. package/bin/validators/Validator.mjs +5 -0
  13. package/bin/validators/index.mjs +2 -0
  14. package/package.json +3 -2
  15. package/src/index.stories.mdx +51 -0
  16. package/templates/{[.npmignore].js → component/[.npmignore].js} +0 -0
  17. package/templates/{[package.json].js → component/[package.json].js} +2 -2
  18. package/templates/{[tsconfig.json].js → component/[tsconfig.json].js} +0 -0
  19. package/templates/{[vite.config.ts].js → component/[vite.config.ts].js} +0 -0
  20. package/templates/{src → component/src}/[Component.stories.mdx].js +4 -4
  21. package/templates/{src → component/src}/[Component.stories.tsx].js +2 -2
  22. package/templates/{src → component/src}/[Component.test.tsx].js +2 -2
  23. package/templates/{src → component/src}/[Component.tsx].js +2 -2
  24. package/templates/component/src/[Component.variants.tsx].js +8 -0
  25. package/templates/{src → component/src}/[index.ts].js +2 -2
  26. package/templates/hook/[.npmignore].js +3 -0
  27. package/templates/hook/[package.json].js +15 -0
  28. package/templates/hook/[tsconfig.json].js +4 -0
  29. package/templates/hook/[vite.config.ts].js +7 -0
  30. package/templates/hook/src/[index.ts].js +8 -0
  31. package/templates/hook/src/[name.stories.mdx].js +42 -0
  32. package/templates/hook/src/[name.test.tsx].js +17 -0
  33. package/templates/hook/src/[name.tsx].js +10 -0
  34. package/templates/util/[.npmignore].js +1 -0
  35. package/templates/util/[package.json].js +15 -0
  36. package/templates/util/[tsconfig.json].js +5 -0
  37. package/templates/util/[vite.config.ts].js +23 -0
  38. package/templates/util/src/[index.ts].js +1 -0
  39. package/templates/src/[Component.variants.tsx].js +0 -8
package/CHANGELOG.md CHANGED
@@ -3,6 +3,16 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [1.4.0](https://github.com/adevinta/spark/compare/@spark-ui/cli-utils@1.3.2...@spark-ui/cli-utils@1.4.0) (2023-02-22)
7
+
8
+ ### Features
9
+
10
+ - **cli-utils:** add hook and utils template ([e22d672](https://github.com/adevinta/spark/commit/e22d672e349909cc4bc8673312846d10d77e7ea5))
11
+
12
+ ## [1.3.2](https://github.com/adevinta/spark/compare/@spark-ui/cli-utils@1.3.1...@spark-ui/cli-utils@1.3.2) (2023-02-22)
13
+
14
+ **Note:** Version bump only for package @spark-ui/cli-utils
15
+
6
16
  ## [1.3.1](https://github.com/adevinta/spark/compare/@spark-ui/cli-utils@1.3.0...@spark-ui/cli-utils@1.3.1) (2023-02-21)
7
17
 
8
18
  **Note:** Version bump only for package @spark-ui/cli-utils
@@ -0,0 +1,19 @@
1
+ import chalk from 'chalk'
2
+
3
+ export class Logger {
4
+ success(message) {
5
+ console.log(chalk.green(message))
6
+ }
7
+
8
+ error(message) {
9
+ console.log(chalk.red(message))
10
+ }
11
+
12
+ info(message) {
13
+ console.log(chalk.yellow(message))
14
+ }
15
+
16
+ warning(message) {
17
+ console.log(chalk.green(message))
18
+ }
19
+ }
@@ -0,0 +1,45 @@
1
+ import fse from 'fs-extra'
2
+ import glob from 'glob'
3
+
4
+ export class System {
5
+ logger
6
+
7
+ constructor({ logger }) {
8
+ this.logger = logger
9
+ }
10
+
11
+ exit(message) {
12
+ this.logger.error(`✖ Error: ${message}\n`)
13
+ process.exit(1)
14
+ }
15
+
16
+ getBasePath() {
17
+ return process.cwd()
18
+ }
19
+
20
+ getPackageJSON() {
21
+ const basePath = this.getBasePath()
22
+
23
+ const raw = fse.readFileSync(`${basePath}/package.json`).toString()
24
+
25
+ return JSON.parse(raw)
26
+ }
27
+
28
+ isPackageCreated(name) {
29
+ const base = this.getBasePath()
30
+ const packageJSON = this.getPackageJSON()
31
+
32
+ return packageJSON.workspaces.some(workspace => {
33
+ const packages = glob.sync(`${base}/${workspace}/`)
34
+
35
+ return packages.some(path => path.endsWith(`/${name}/`))
36
+ })
37
+ }
38
+
39
+ writeFile({ path, content }) {
40
+ return fse
41
+ .outputFile(path, content)
42
+ .then(() => this.logger.info(`Created ${path}`))
43
+ .catch(error => this.exit(`Failed creating ${path}`))
44
+ }
45
+ }
@@ -0,0 +1,2 @@
1
+ export { Logger } from './Logger.mjs'
2
+ export { System } from './System.mjs'
@@ -0,0 +1,5 @@
1
+ export class Generator {
2
+ execute() {
3
+ throw new Error('execute method should be implemented')
4
+ }
5
+ }
@@ -0,0 +1,83 @@
1
+ import { join } from 'node:path'
2
+ import { fileURLToPath } from 'node:url'
3
+ import glob from 'glob'
4
+ import { pascalCase } from 'pascal-case'
5
+ import { camelCase } from 'camel-case'
6
+
7
+ import { System } from '../core/index.mjs'
8
+ import { Generator } from './Generator.mjs'
9
+
10
+ export class TemplateGenerator extends Generator {
11
+ static TYPES = {
12
+ COMPONENT: 'component',
13
+ HOOK: 'hook',
14
+ UTIL: 'util',
15
+ }
16
+
17
+ static CONTEXTS = {
18
+ [TemplateGenerator.TYPES.COMPONENT]: 'components',
19
+ [TemplateGenerator.TYPES.HOOK]: 'components',
20
+ [TemplateGenerator.TYPES.UTIL]: 'utils',
21
+ }
22
+
23
+ constructor({ system }) {
24
+ super()
25
+ this.system = system
26
+ }
27
+
28
+ getDest({ type, name }) {
29
+ const basePath = this.system.getBasePath()
30
+ const context = TemplateGenerator.CONTEXTS[type]
31
+
32
+ return `${basePath}/packages/${context}/${name}`
33
+ }
34
+
35
+ getTemplatePaths({ type }) {
36
+ const pattern = fileURLToPath(new URL(`../../templates/${type}/**/*.js`, import.meta.url))
37
+
38
+ return new Promise((resolve, reject) => {
39
+ glob(pattern, async (error, paths) => {
40
+ if (error) {
41
+ return reject(error)
42
+ }
43
+
44
+ resolve(paths)
45
+ })
46
+ })
47
+ }
48
+
49
+ getTemplatePath({ path, name, type, dest }) {
50
+ const parsed = path
51
+ .replace(/(.*)\/templates\/([a-z-]+)\//, `${dest}/`)
52
+ .replaceAll(/\[|\]|\.js$/g, '')
53
+
54
+ if (type === TemplateGenerator.TYPES.COMPONENT) {
55
+ return parsed.replace('Component', pascalCase(name))
56
+ }
57
+
58
+ if (type === TemplateGenerator.TYPES.HOOK) {
59
+ return parsed.replace('name', camelCase(name))
60
+ }
61
+
62
+ return parsed
63
+ }
64
+
65
+ async execute({ type, name, description }) {
66
+ const dest = this.getDest({ type, name })
67
+ const paths = await this.getTemplatePaths({ type })
68
+
69
+ const promises = paths.map(path =>
70
+ import(path).then(module => ({
71
+ path: this.getTemplatePath({ path, name, type, dest }),
72
+ content: module.default({
73
+ name,
74
+ description,
75
+ }),
76
+ }))
77
+ )
78
+
79
+ const files = await Promise.all(promises)
80
+
81
+ return Promise.all(files.map(file => this.system.writeFile(file)))
82
+ }
83
+ }
@@ -0,0 +1,2 @@
1
+ export { Generator } from './Generator.mjs'
2
+ export { TemplateGenerator } from './TemplateGenerator.mjs'
@@ -1,156 +1,71 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import chalk from 'chalk'
4
- import fse from 'fs-extra'
5
3
  import * as prompt from '@clack/prompts'
6
- import { fileURLToPath } from 'node:url'
7
- import glob from 'glob'
8
- import { pascalCase } from 'pascal-case'
9
- import { log, showError, writeFile } from '../utils.js'
10
4
 
11
- const BASE_DIR = process.cwd()
12
- const rawRootPackageJSON = fse.readFileSync(`${BASE_DIR}/package.json`)
13
- let rootPackageJSON = JSON.parse(rawRootPackageJSON)
5
+ import { TemplateGenerator } from './generators/index.mjs'
6
+ import { Logger, System } from './core/index.mjs'
7
+ import { DescriptionValidator, NameValidator } from './validators/index.mjs'
14
8
 
15
- const TEMPLATE_TYPE = {
16
- COMPONENT: 'component',
17
- HOOK: 'hook',
18
- }
19
-
20
- const WORKSPACES = {
21
- [TEMPLATE_TYPE.COMPONENT]: '/packages/components',
22
- [TEMPLATE_TYPE.HOOK]: '/packages/hooks',
23
- }
24
-
25
- const ERRORS = {
26
- ABORT: 'Aborted package generation',
27
- NO_PKG_NAME: 'Package name must me defined',
28
- INVALID_PKG_NAME: 'Name name must contain letters and dash symbols only (ex: "my-package")',
29
- INVALID_DESCRIPTION: 'Description is too short (minimum is 10 chars)',
30
- PKG_ALREADY_EXISTS:
31
- 'A package with that name already exists. Either delete it manually or use another name.',
32
- }
33
-
34
- const packageUtils = {
35
- /** Validate the format of the package name (kebab case format) */
36
- hasValidName: name => /^[a-z-]*$/.test(name),
37
- /** Check that a package of the same name does not exists across all workspaces */
38
- alreadyExists: name => {
39
- return rootPackageJSON.workspaces.some(workspace => {
40
- const existingPackages = glob.sync(`${BASE_DIR}/${workspace}/`)
41
- return existingPackages.some(path => path.endsWith(`/${name}/`))
42
- })
43
- },
44
- /** Retrieves the target folder of the generated package */
45
- getDirectory: (name, template) => `${WORKSPACES[template]}/${name}/`,
46
- /** Retrieves the full path to the folder of the generated package */
47
- getFullPath: (name, template) => `${BASE_DIR}${packageUtils.getDirectory(name, template)}`,
48
- }
9
+ const logger = new Logger()
10
+ const system = new System({ logger })
11
+ const generator = new TemplateGenerator({ system })
49
12
 
50
- async function promptPackageName() {
13
+ export const run = async () => {
51
14
  const name = await prompt.text({
52
15
  message: 'Package name (must contain letters and dash symbols only):',
53
16
  initialValue: '',
54
17
  validate(value) {
55
- if (value == null) return ERRORS.NO_PKG_NAME
56
- if (!packageUtils.hasValidName(value)) return ERRORS.INVALID_PKG_NAME
57
- if (packageUtils.alreadyExists(value)) return ERRORS.PKG_ALREADY_EXISTS
18
+ const validator = new NameValidator({ system })
19
+
20
+ return validator.validate(value)
58
21
  },
59
22
  })
60
23
 
61
- if (prompt.isCancel(name)) showError(ERRORS.ABORT)
62
-
63
- return name
64
- }
24
+ if (prompt.isCancel(name)) {
25
+ system.exit('Aborted package generation')
26
+ }
65
27
 
66
- async function promptPackageTemplate() {
67
- const template = await prompt.select({
28
+ const type = await prompt.select({
68
29
  message: 'Chose a template:',
69
- initialValue: TEMPLATE_TYPE.COMPONENT,
30
+ initialValue: 'component',
70
31
  options: [
71
32
  {
72
- value: TEMPLATE_TYPE.COMPONENT,
33
+ value: TemplateGenerator.TYPES.COMPONENT,
73
34
  label: 'Component',
74
- hint: 'Typescript dummy component with some tests, stories and config files',
35
+ hint: 'TypeScript component package',
75
36
  },
76
37
  {
77
- value: TEMPLATE_TYPE.HOOK,
38
+ value: TemplateGenerator.TYPES.HOOK,
78
39
  label: 'Hook',
79
- hint: 'Typescript hook with some tests, stories and config files',
40
+ hint: 'TypeScript hook package',
41
+ },
42
+ {
43
+ value: TemplateGenerator.TYPES.UTIL,
44
+ label: 'Utility',
45
+ hint: 'TypeScript utility package',
80
46
  },
81
47
  ],
82
48
  })
83
49
 
84
- if (prompt.isCancel(template)) showError(ERRORS.ABORT)
85
-
86
- return template
87
- }
50
+ if (prompt.isCancel(type)) {
51
+ system.exit('Aborted package generation')
52
+ }
88
53
 
89
- async function promptPackageDescription() {
90
54
  const description = await prompt.text({
91
55
  message: 'Describe your package (short description):',
92
56
  initialValue: '',
93
57
  validate(value) {
94
- if (!value) return `You package must have a description`
95
- if (value.length < 10) return ERRORS.INVALID_DESCRIPTION
58
+ const validator = new DescriptionValidator()
59
+
60
+ return validator.validate(value)
96
61
  },
97
62
  })
98
63
 
99
- if (prompt.isCancel(description)) showError(ERRORS.ABORT)
100
-
101
- return description
102
- }
103
-
104
- /**
105
- * Program starts here
106
- */
107
- prompt.intro(`Generate Spark package`)
108
-
109
- const name = await promptPackageName()
110
- const template = await promptPackageTemplate()
111
- const description = await promptPackageDescription()
112
-
113
- const packagePath = packageUtils.getFullPath(name, template)
114
-
115
- switch (template) {
116
- case TEMPLATE_TYPE.COMPONENT:
117
- generateComponentPackage(name, description)
118
- break
119
- case TEMPLATE_TYPE.HOOK:
120
- generateHookPackage(name, description)
121
- break
122
- }
123
-
124
- prompt.outro(`Generating package...`)
125
-
126
- function generateComponentPackage(name, description) {
127
- const templatesPattern = fileURLToPath(new URL('../templates/**/*.js', import.meta.url))
128
-
129
- glob(templatesPattern, async (err, res) => {
130
- if (err) showError(err)
131
- if (res) {
132
- const templateContents = res.map(templatePath =>
133
- import(templatePath).then(module => ({
134
- path: templatePath
135
- .replace(/(.*)\/templates\//, packagePath)
136
- .replace('Component', pascalCase(name))
137
- .replaceAll(/\[|\]|\.js$/g, ''),
138
- content: module.default({
139
- component: name,
140
- description: description,
141
- }),
142
- }))
143
- )
64
+ if (prompt.isCancel(description)) {
65
+ system.exit('Aborted package generation')
66
+ }
144
67
 
145
- const filesToWrite = await Promise.all(templateContents)
146
-
147
- Promise.all(filesToWrite.map(writeFile)).then(() => {
148
- log.success('All package files has been properly written!')
149
- })
150
- }
151
- })
68
+ generator.execute({ name, type, description })
152
69
  }
153
70
 
154
- function generateHookPackage(name, description) {
155
- showError('Todo: template for hook packages is not ready yet.')
156
- }
71
+ run()
@@ -5,7 +5,8 @@ import { join, extname, parse, sep } from 'path'
5
5
  import { readFileSync, readdirSync, writeFileSync, unlinkSync } from 'fs'
6
6
  import { transformSync } from 'esbuild'
7
7
 
8
- import { log, showError } from '../utils.js'
8
+ const logger = new Logger()
9
+ const system = new System({ logger })
9
10
 
10
11
  const jsFileExtension = '.js'
11
12
 
@@ -14,7 +15,7 @@ const configFile = readdirSync(process.cwd()).find(fileName =>
14
15
  )
15
16
 
16
17
  if (!configFile) {
17
- showError(
18
+ system.exit(
18
19
  "We couldn't find a `spark.theme.config` file in this folder. Please make sure that the file is located in the root folder of your project"
19
20
  )
20
21
  }
@@ -24,8 +25,9 @@ const filePath = join(process.cwd(), configFile)
24
25
 
25
26
  const allowedExtensions = ['.ts', '.mts', '.cts', '.js', '.cjs', '.mjs']
26
27
  const fileExtension = extname(filePath)
28
+
27
29
  if (!allowedExtensions.includes(fileExtension)) {
28
- showError(`Your spark.theme.config file extension (${fileExtension}) is not supported.`)
30
+ system.exit(`Your spark.theme.config file extension (${fileExtension}) is not supported.`)
29
31
  }
30
32
 
31
33
  const tsCode = readFileSync(filePath, 'utf-8')
@@ -42,6 +44,6 @@ const child = spawn(process.execPath, [jsFilePath], {
42
44
 
43
45
  child.on('exit', code => {
44
46
  if (!configFileIsInJS) unlinkSync(jsFilePath)
45
- log.success('✨ Your Spark theme config files have been successfully created!')
47
+ logger.success('✨ Your Spark theme config files have been successfully created!')
46
48
  process.exit(code)
47
49
  })
@@ -0,0 +1,19 @@
1
+ import { Validator } from './Validator.mjs'
2
+
3
+ export class DescriptionValidator extends Validator {
4
+ constructor() {
5
+ super()
6
+ }
7
+
8
+ validate(description) {
9
+ if (!description) {
10
+ return 'You package must have a description'
11
+ }
12
+
13
+ if (description.length < 10) {
14
+ return 'Description is too short (minimum is 10 chars)'
15
+ }
16
+
17
+ return undefined
18
+ }
19
+ }
@@ -0,0 +1,25 @@
1
+ import { System } from '../core/index.mjs'
2
+ import { Validator } from './Validator.mjs'
3
+
4
+ export class NameValidator extends Validator {
5
+ system
6
+
7
+ constructor({ system }) {
8
+ super()
9
+ this.system = system
10
+ }
11
+
12
+ validate(name) {
13
+ if (!name) {
14
+ return 'Package name must me defined'
15
+ }
16
+
17
+ if (!/^[a-z-]*$/.test(name)) {
18
+ return 'Name name must contain letters and dash symbols only (ex: "my-package")'
19
+ }
20
+
21
+ if (this.system.isPackageCreated(name)) {
22
+ return 'A package with that name already exists. Either delete it manually or use another name.'
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,5 @@
1
+ export class Validator {
2
+ validate() {
3
+ throw new Error('validate method should be implemented')
4
+ }
5
+ }
@@ -0,0 +1,2 @@
1
+ export { NameValidator } from './NameValidator.mjs'
2
+ export { DescriptionValidator } from './DescriptionValidator.mjs'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spark-ui/cli-utils",
3
- "version": "1.3.1",
3
+ "version": "1.4.0",
4
4
  "description": "Spark CLI utils",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -13,6 +13,7 @@
13
13
  "type": "module",
14
14
  "dependencies": {
15
15
  "@clack/prompts": "0.2.2",
16
+ "camel-case": "4.1.2",
16
17
  "chalk": "5.2.0",
17
18
  "commander": "10.0.0",
18
19
  "esbuild": "0.17.8",
@@ -25,5 +26,5 @@
25
26
  "url": "git@github.com:adevinta/spark.git",
26
27
  "directory": "packages/utils/cli"
27
28
  },
28
- "gitHead": "6667269271cbbc620443701a6de33587938901e9"
29
+ "gitHead": "61d037acf7909f745ced1d1a0196fe6d2838850e"
29
30
  }
@@ -0,0 +1,51 @@
1
+ import { Meta } from '@storybook/blocks'
2
+ import { StoryHeading } from '@docs/helpers/StoryHeading'
3
+
4
+ <Meta title="utils/CLI" />
5
+
6
+ # CLI utils
7
+
8
+ This package provides some CLI commands to improve the development experience when building the Spark design system. Right now there are some different commands available:
9
+
10
+ - A command for generating new components: `$ spark generate`.
11
+ - A command for doing the initial setup for a new theme: `$ spark setup-theme`.
12
+
13
+ ## Contents
14
+
15
+ - [Installation](#installation)
16
+ - [Generating a new package](#generating-a-new-package)
17
+ - [Setting up a theme](#setting-up-a-theme)
18
+
19
+ <StoryHeading label="Installation" as="h2" />
20
+
21
+ CLI utils can be used by installing the package `@spark-ui/cli-utils` in your project:
22
+
23
+ ```bash
24
+ $ npm install --save-dev @spark-ui/cli-utils
25
+ ```
26
+
27
+ or just by running the following command:
28
+
29
+ ```bash
30
+ $ npx spark COMMAND_NAME
31
+ ```
32
+
33
+ <StoryHeading label="Generating a new package" as="h2" />
34
+
35
+ In order to generate a new package, the following command has to be executed:
36
+
37
+ ```bash
38
+ $ spark generate
39
+ ```
40
+
41
+ Then, a command prompt will guide you through the process by asking you for:
42
+
43
+ - the package name (required),
44
+ - the template used (required, only `Component` template available right now)
45
+ - and the package description (optional).
46
+
47
+ <StoryHeading label="Setting up a theme" as="h2" />
48
+
49
+ ```bash
50
+ $ spark setup-theme
51
+ ```
@@ -1,5 +1,5 @@
1
- export default ({ component, description }) => `{
2
- "name": "@spark-ui/${component}",
1
+ export default ({ name, description }) => `{
2
+ "name": "@spark-ui/${name}",
3
3
  "version": "1.0.0",
4
4
  "description": "${description}",
5
5
  "publishConfig": {
@@ -1,7 +1,7 @@
1
1
  import { pascalCase } from 'pascal-case'
2
2
 
3
- export default ({ component, description }) => {
4
- const componentName = pascalCase(component)
3
+ export default ({ name, description }) => {
4
+ const componentName = pascalCase(name)
5
5
 
6
6
  return `import { ArgsTable, Meta, Story } from '@storybook/addon-docs'
7
7
  import { ReactLiveBlock } from '@docs/helpers/ReactLiveBlock'
@@ -20,13 +20,13 @@ ${description}
20
20
  <StoryHeading label="Install" />
21
21
 
22
22
  \`\`\`
23
- npm install @spark-ui/${component}
23
+ npm install @spark-ui/${name}
24
24
  \`\`\`
25
25
 
26
26
  <StoryHeading label="Import" />
27
27
 
28
28
  \`\`\`
29
- import { ${componentName} } from "@spark-ui/${component}"
29
+ import { ${componentName} } from "@spark-ui/${name}"
30
30
  \`\`\`
31
31
 
32
32
  <StoryHeading label="Props" />
@@ -1,7 +1,7 @@
1
1
  import { pascalCase } from 'pascal-case'
2
2
 
3
- export default ({ component, description }) => {
4
- const componentName = pascalCase(component)
3
+ export default ({ name, description }) => {
4
+ const componentName = pascalCase(name)
5
5
 
6
6
  return `import { ReactLiveBlock } from '@docs/helpers/ReactLiveBlock'
7
7
 
@@ -1,7 +1,7 @@
1
1
  import { pascalCase } from 'pascal-case'
2
2
 
3
- export default ({ component }) => {
4
- const componentName = pascalCase(component)
3
+ export default ({ name }) => {
4
+ const componentName = pascalCase(name)
5
5
 
6
6
  return `import { render, screen } from '@testing-library/react'
7
7
  import userEvent from '@testing-library/user-event'
@@ -1,7 +1,7 @@
1
1
  import { pascalCase } from 'pascal-case'
2
2
 
3
- export default ({ component }) => {
4
- const componentName = pascalCase(component)
3
+ export default ({ name }) => {
4
+ const componentName = pascalCase(name)
5
5
 
6
6
  return `import { ComponentPropsWithoutRef, PropsWithChildren } from 'react'
7
7
 
@@ -0,0 +1,8 @@
1
+ import { pascalCase } from 'pascal-case'
2
+
3
+ export default ({ name }) => {
4
+ const componentName = pascalCase(name)
5
+
6
+ return `
7
+ `
8
+ }
@@ -1,7 +1,7 @@
1
1
  import { pascalCase } from 'pascal-case'
2
2
 
3
- export default ({ component }) => {
4
- const componentName = pascalCase(component)
3
+ export default ({ name }) => {
4
+ const componentName = pascalCase(name)
5
5
 
6
6
  return `export { ${componentName} } from './${componentName}'
7
7
  `
@@ -0,0 +1,3 @@
1
+ export default () => `src
2
+ **/*.stories.*
3
+ `
@@ -0,0 +1,15 @@
1
+ export default ({ name, description }) => `{
2
+ "name": "@spark-ui/${name}",
3
+ "version": "1.0.0",
4
+ "description": "${description}",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "main": "./dist/index.js",
9
+ "module": "./dist/index.mjs",
10
+ "types": "./dist/index.d.ts",
11
+ "scripts": {
12
+ "build": "vite build"
13
+ }
14
+ }
15
+ `
@@ -0,0 +1,4 @@
1
+ export default () => `{
2
+ "extends": "../../../tsconfig.json",
3
+ "include": ["src/**/*", "../../../global.d.ts"]
4
+ }`
@@ -0,0 +1,7 @@
1
+ export default () => `import path from 'path'
2
+ import { getComponentConfiguration } from '../../../config/index'
3
+
4
+ const { name } = require(path.resolve(__dirname, 'package.json'))
5
+
6
+ export default getComponentConfiguration(name)
7
+ `
@@ -0,0 +1,8 @@
1
+ import { camelCase } from 'camel-case'
2
+
3
+ export default ({ name }) => {
4
+ const hookName = camelCase(name)
5
+
6
+ return `export { ${hookName} } from './${hookName}'
7
+ `
8
+ }
@@ -0,0 +1,42 @@
1
+ import { camelCase } from 'camel-case'
2
+
3
+ export default ({ name, description }) => {
4
+ const hookName = camelCase(name)
5
+
6
+ return `import { ArgsTable, Meta, Story } from '@storybook/addon-docs'
7
+ import { ReactLiveBlock } from '@docs/helpers/ReactLiveBlock'
8
+ import { StoryHeading } from '@docs/helpers/StoryHeading'
9
+
10
+ import { ${hookName} } from '.'
11
+
12
+ import * as stories from './${hookName}.stories'
13
+
14
+ <Meta title="Hooks/${hookName}" />
15
+
16
+ # ${hookName}
17
+
18
+ ${description}
19
+
20
+ <StoryHeading label="Install" />
21
+
22
+ \`\`\`
23
+ npm install @spark-ui/${name}
24
+ \`\`\`
25
+
26
+ <StoryHeading label="Import" />
27
+
28
+ \`\`\`
29
+ import { ${hookName} } from "@spark-ui/${name}"
30
+ \`\`\`
31
+
32
+ <StoryHeading label="Usage" />
33
+
34
+ <ArgsTable of={${hookName}} />
35
+
36
+ \`\`\`jsx
37
+ import { ${hookName} } from "@spark-ui/${name}"
38
+
39
+ const Demo = () => {}
40
+ \`\`\`
41
+ `
42
+ }
@@ -0,0 +1,17 @@
1
+ import { camelCase } from 'camel-case'
2
+
3
+ export default ({ name }) => {
4
+ const hookName = camelCase(name)
5
+
6
+ return `import { renderHook } from '@testing-library/react'
7
+ import { describe, expect, it } from 'vitest'
8
+
9
+ import { ${hookName} } from './${hookName}'
10
+
11
+ describe('${hookName}', () => {
12
+ it('should be defined', () => {
13
+ expect(${hookName}).toBeDefined()
14
+ })
15
+ })
16
+ `
17
+ }
@@ -0,0 +1,10 @@
1
+ import { camelCase } from 'camel-case'
2
+
3
+ export default ({ name }) => {
4
+ const hookName = camelCase(name)
5
+
6
+ return `export function ${hookName}() {
7
+ return null
8
+ }
9
+ `
10
+ }
@@ -0,0 +1 @@
1
+ export default () => 'src'
@@ -0,0 +1,15 @@
1
+ export default ({ name, description }) => `{
2
+ "name": "@spark-ui/${name}",
3
+ "version": "1.0.0",
4
+ "description": "${description}",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "main": "./dist/index.js",
9
+ "module": "./dist/index.mjs",
10
+ "types": "./dist/index.d.ts",
11
+ "scripts": {
12
+ "build": "vite build"
13
+ }
14
+ }
15
+ `
@@ -0,0 +1,5 @@
1
+ export default () => `{
2
+ "extends": "../../../tsconfig.json",
3
+ "include": ["src/**/*", "../../global.d.ts"]
4
+ }
5
+ `
@@ -0,0 +1,23 @@
1
+ export default () => `import { terser } from 'rollup-plugin-terser'
2
+ import dts from 'vite-plugin-dts'
3
+
4
+ export default {
5
+ build: {
6
+ target: 'es2015',
7
+ lib: {
8
+ entry: 'src/index.ts',
9
+ formats: ['es', 'cjs'],
10
+ fileName: 'index',
11
+ },
12
+ rollupOptions: {
13
+ external: ['node:path', 'node:fs'],
14
+ plugins: [terser()],
15
+ },
16
+ },
17
+ plugins: [
18
+ dts({
19
+ entryRoot: './src',
20
+ }),
21
+ ],
22
+ }
23
+ `
@@ -0,0 +1 @@
1
+ export default () => ''
@@ -1,8 +0,0 @@
1
- import { pascalCase } from 'pascal-case'
2
-
3
- export default ({ component }) => {
4
- const componentName = pascalCase(component)
5
-
6
- return `
7
- `
8
- }