From 7b03e134b6151bfd2029dca7371f6d29f0714b6c Mon Sep 17 00:00:00 2001 From: Isac Petinate Date: Fri, 21 Jun 2024 15:59:52 -0300 Subject: [PATCH] refactor: add new assets and init with examples --- .clingon/presets/generator.json | 18 -- .clingon/presets/util.json | 18 -- .clingon/templates/README.md | 114 ----------- .clingon/templates/component/Component.tsx | 13 -- .clingon/templates/docs/ReactHookDoc.md | 5 - .clingon/templates/meta.yaml | 41 ---- clingon.config.json | 3 - src/actions/init.js | 11 +- src/constants/init.js | 44 +++++ src/flows/coldStart.js | 12 +- src/templates/core/clingon.config.json | 6 + .../core}/functions/AsyncFunction.spec.ts | 0 .../core}/functions/AsyncFunction.ts | 0 src/templates/core/global-config.js | 18 -- src/templates/core/markdown/HookDoc.md | 27 +++ src/templates/core/meta.yaml | 38 ++-- .../react-component}/Component.stories.tsx | 0 .../react-component}/Component.styles.css | 0 .../core/react-component}/Component.test.tsx | 0 .../core/react-component/Component.tsx | 13 ++ .../templates/core/react-component}/index.tsx | 0 src/utils/init-action.js | 180 ++++++++++-------- 22 files changed, 231 insertions(+), 330 deletions(-) delete mode 100644 .clingon/presets/generator.json delete mode 100644 .clingon/presets/util.json delete mode 100644 .clingon/templates/README.md delete mode 100644 .clingon/templates/component/Component.tsx delete mode 100644 .clingon/templates/docs/ReactHookDoc.md delete mode 100644 .clingon/templates/meta.yaml delete mode 100644 clingon.config.json create mode 100644 src/constants/init.js create mode 100644 src/templates/core/clingon.config.json rename {.clingon/templates => src/templates/core}/functions/AsyncFunction.spec.ts (100%) rename {.clingon/templates => src/templates/core}/functions/AsyncFunction.ts (100%) delete mode 100644 src/templates/core/global-config.js create mode 100644 src/templates/core/markdown/HookDoc.md rename {.clingon/templates/component => src/templates/core/react-component}/Component.stories.tsx (100%) rename {.clingon/templates/component => src/templates/core/react-component}/Component.styles.css (100%) rename {.clingon/templates/component => src/templates/core/react-component}/Component.test.tsx (100%) rename {.clingon/templates/component => src/templates/core/react-component}/index.tsx (100%) diff --git a/.clingon/presets/generator.json b/.clingon/presets/generator.json deleted file mode 100644 index ec4e872..0000000 --- a/.clingon/presets/generator.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "framework": null, - "cssFramework": "css_vanilla", - "testFramework": "jest", - "version": null, - "name": "scaffold-template", - "resourcePath": "src/generators", - "testPath": "src/generators", - "storyPath": null, - "testPostfix": "test", - "storyPostfix": "stories", - "type": "function", - "typescript": false, - "withStory": false, - "withTest": true, - "withTestingLibrary": false, - "folderWrapper": false -} diff --git a/.clingon/presets/util.json b/.clingon/presets/util.json deleted file mode 100644 index a1712f4..0000000 --- a/.clingon/presets/util.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "framework": null, - "cssFramework": "css_vanilla", - "testFramework": "jest", - "version": null, - "name": "scaffold-template", - "resourcePath": "src/utils", - "testPath": "src/utils", - "storyPath": null, - "testPostfix": "test", - "storyPostfix": "stories", - "type": "function", - "typescript": false, - "withStory": false, - "withTest": true, - "withTestingLibrary": false, - "folderWrapper": false -} diff --git a/.clingon/templates/README.md b/.clingon/templates/README.md deleted file mode 100644 index 19e1c90..0000000 --- a/.clingon/templates/README.md +++ /dev/null @@ -1,114 +0,0 @@ -# Documentation for Local Resource Creation - -This documentation describes how to use the `meta.yaml` file to create local resources based on templates found in the `.clingon/templates` folder. - -## Structure of the `meta.yaml` File - -The `meta.yaml` file contains definitions of resources that the CLI tool uses to generate components, pages, async functions, or whatever you want. - -## Field Details - -The table below describes the fields used in the resource definitions in the `meta.yaml` file. - -| Field | Type | Required | Description | -| ----------------------- | ------- | ------------------------ | --------------------------------------------------------------------- | -| `identifier` | string | Yes | Unique identifier for the resource. | -| `folderWrapper` | boolean | No | Indicates if the resource should be wrapped by a folder. | -| `resource` | object | Yes | Contains information about the main resource. | -| `resource.target` | string | Yes | Target directory where the resource will be generated. | -| `resource.templatePath` | string | Yes | Path to the resource template. | -| `test` | object | No | Contains information about the resource's test file. | -| `test.target` | string | Yes (if `test` present) | Target directory where the test will be generated. | -| `test.templatePath` | string | Yes (if `test` present) | Path to the test template. | -| `story` | object | No | Contains information about the resource's story file (for Storybook). | -| `story.target` | string | Yes (if `story` present) | Target directory where the story will be generated. | -| `story.templatePath` | string | Yes (if `story` present) | Path to the story template. | - -## Detailed Examples - -### React Component - -```yaml -- identifier: component - folderWrapper: true - resource: - target: src/components - templatePath: ./ReactComponent/Component.tsx - test: - target: src/components - templatePath: ./ReactComponent/Component.spec.tsx - story: - target: src/components - templatePath: ./ReactComponent/Component.stories.tsx -``` - -- **identifier**: `component` -- **folderWrapper**: `true` -- **resource**: - - **target**: `src/components` - - **templatePath**: `./ReactComponent/Component.tsx` -- **test**: - - **target**: `src/components` - - **templatePath**: `./ReactComponent/Component.spec.tsx` -- **story**: - - **target**: `src/components` - - **templatePath**: `./ReactComponent/Component.stories.tsx` - -### Asynchronous Function - -```yaml -- identifier: async-function - resource: - target: src/utils - templatePath: ./Functions/AsyncFunction.ts - test: - target: src/utils - templatePath: ./Functions/AsyncFunction.spec.ts -``` - -- **identifier**: `async-function` -- **resource**: - - **target**: `src/utils` - - **templatePath**: `./Functions/AsyncFunction.ts` -- **test**: - - **target**: `src/utils` - - **templatePath**: `./Functions/AsyncFunction.spec.ts` - -### Markdown Documentation - -```yaml -- identifier: markdown - resource: - target: src/docs - templatePath: ./Docs/ReactHookDoc.md -``` - -- **identifier**: `markdown` -- **resource**: - - **target**: `src/docs` - - **templatePath**: `./Docs/ReactHookDoc.md` - -### `.nvmrc` File - -```yaml -- identifier: nvmrc - resource: - target: . - templatePath: ./Core/.nvmrc -``` - -- **identifier**: `nvmrc` -- **resource**: - - **target**: `.` - - **templatePath**: `./Core/.nvmrc` - -## How to Use - -1. Place the `meta.yaml` or `meta.json` (I strongly recommend using YAML, but you can use JSON) file in the `.clingon/templates` folder along with your templates. -2. Run the CLI tool according to your project's instructions to generate the resources defined in the `meta` file. - - ```shell - npx clingon scaffold --template - ``` - -This structure allows for easy definition and generation of different types of resources in your project, ensuring consistency and organization. diff --git a/.clingon/templates/component/Component.tsx b/.clingon/templates/component/Component.tsx deleted file mode 100644 index cfeec33..0000000 --- a/.clingon/templates/component/Component.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import './ResourceName.styles.css' - -export interface ResourceNameProps { - message: string -} - -export function ResourceName({ message }: ResourceNameProps) { - return ( -
-

{message}

-
- ) -} diff --git a/.clingon/templates/docs/ReactHookDoc.md b/.clingon/templates/docs/ReactHookDoc.md deleted file mode 100644 index 31f9821..0000000 --- a/.clingon/templates/docs/ReactHookDoc.md +++ /dev/null @@ -1,5 +0,0 @@ -# ResourceName - -> My hook doc - -- Test generate with MD file diff --git a/.clingon/templates/meta.yaml b/.clingon/templates/meta.yaml deleted file mode 100644 index dd8bdb0..0000000 --- a/.clingon/templates/meta.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# ┌-----------------------------------------------------------------┐ -# ⎪ Auto generated by Clingon CLI ⎪ -# ⎪ This file is only a example, feel free to edit them ⎪ -# ⎪ ⎪ -# ⎪ In the README file you will find more details and a complete ⎪ -# ⎪ guide on how to use this feature: .clingon/templates/README.md ⎪ -# ⎪ ------------------------------- ⎪ -# ⎪ AFTER READ, REMOVE THIS SECTION ⎪ -# └-----------------------------------------------------------------┘ - -# Component - -- identifier: component - folderWrapper: true - resources: - - path: src/components - template: ./component/index.tsx - - path: src/components - template: ./component/Component.tsx - - path: src/components - template: ./component/Component.test.tsx - - path: src/components - template: ./component/Component.stories.tsx - - path: src/components - template: ./component/Component.styles.css - -# Async Function - -- identifier: async-function - resources: - - path: src/utils - template: ./functions/AsyncFunction.ts - - path: src/utils - template: ./functions/AsyncFunction.spec.ts - -# Markdown - -- identifier: hook-doc - resources: - - path: src/docs/hooks - template: ./docs/ReactHookDoc.md diff --git a/clingon.config.json b/clingon.config.json deleted file mode 100644 index 357ab06..0000000 --- a/clingon.config.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "exportDefault": false -} diff --git a/src/actions/init.js b/src/actions/init.js index 2c49c00..de989f5 100644 --- a/src/actions/init.js +++ b/src/actions/init.js @@ -4,9 +4,9 @@ import { checkIfTemplateFolderAlreadyExists, createFileIfNotExists, createPresetFolderIfNotExists, + createPresetsFolderAssets, createTemplateFolderAssets, createTemplateFolderIfNotExists, - getConfigContent, getConfigFilePath } from '../utils/init-action.js' @@ -19,11 +19,7 @@ export async function initAction(options) { * Global Config */ - compose( - getConfigFilePath(options.examples), - createFileIfNotExists, - getConfigContent - ) + compose(getConfigFilePath(options.examples), createFileIfNotExists) /* * Preset Folder @@ -31,7 +27,8 @@ export async function initAction(options) { compose( checkIfPresetFolderAlreadyExists(options.examples), - createPresetFolderIfNotExists + createPresetFolderIfNotExists, + createPresetsFolderAssets ) /* diff --git a/src/constants/init.js b/src/constants/init.js new file mode 100644 index 0000000..2df77d8 --- /dev/null +++ b/src/constants/init.js @@ -0,0 +1,44 @@ +export const templateCoreFiles = [ + { + folder: 'templates/core/functions', + target: 'functions', + files: ['AsyncFunction.ts', 'AsyncFunction.spec.ts'] + }, + { + folder: 'templates/core/markdown', + target: 'docs', + files: ['HookDoc.md'] + }, + { + folder: 'templates/core/react-component', + target: 'component/react-component', + files: [ + 'index.tsx', + 'Component.tsx', + 'Component.test.tsx', + 'Component.styles.css', + 'Component.stories.tsx' + ] + }, + { + folder: 'templates/core', + target: '', + files: ['meta.yaml', 'SCAFFOLD_GUIDE.md'] + } +] + +export const presetsCoreFiles = [ + { + folder: 'templates/core', + target: '', + files: ['PRESETS_GUIDE.md', 'function-preset.json'] + } +] + +export const globalCoreFiles = [ + { + folder: 'templates/core', + target: '', + files: ['clingon.config.json'] + } +] diff --git a/src/flows/coldStart.js b/src/flows/coldStart.js index e3c7bec..5b7969e 100644 --- a/src/flows/coldStart.js +++ b/src/flows/coldStart.js @@ -1,6 +1,5 @@ import { join } from 'node:path' -import { readFileContent } from '../utils/file.js' -import { getConfigContent } from '../utils/init-action.js' +import { checkFileExists, readFileContent } from '../utils/file.js' export async function coldStart() { const configPath = join(process.cwd(), 'clingon.config.json') @@ -16,7 +15,14 @@ export async function coldStart() { } try { - data.globalConfig = getConfigContent(configPath) + const exists = checkFileExists(configPath) + + if (!exists) return { globalConfig: null } + + const fileContent = readFileContent(configPath) + const fileContentParsed = JSON.parse(fileContent) + + data.globalConfig = fileContentParsed } catch (error) { console.error(error) } diff --git a/src/templates/core/clingon.config.json b/src/templates/core/clingon.config.json new file mode 100644 index 0000000..b46987e --- /dev/null +++ b/src/templates/core/clingon.config.json @@ -0,0 +1,6 @@ +{ + "alias": { + "src": "@" + }, + "exportDefault": false +} diff --git a/.clingon/templates/functions/AsyncFunction.spec.ts b/src/templates/core/functions/AsyncFunction.spec.ts similarity index 100% rename from .clingon/templates/functions/AsyncFunction.spec.ts rename to src/templates/core/functions/AsyncFunction.spec.ts diff --git a/.clingon/templates/functions/AsyncFunction.ts b/src/templates/core/functions/AsyncFunction.ts similarity index 100% rename from .clingon/templates/functions/AsyncFunction.ts rename to src/templates/core/functions/AsyncFunction.ts diff --git a/src/templates/core/global-config.js b/src/templates/core/global-config.js deleted file mode 100644 index 6c0056f..0000000 --- a/src/templates/core/global-config.js +++ /dev/null @@ -1,18 +0,0 @@ -export const defaultConfig = { - /** - * Alias for text ocurrences replacement - * - * 🚨 Be careful, do not replace "resourcePath" or "ResourceName", to avoid generating strange behavior in the templates, - * causing auto-completion to be unconfigured - */ - alias: { - /** - * Will replace all `src` occurrences on templates to `@`, Example: `src/components/...` become `@/components/...` - */ - src: '@' - }, - /** - * If `true` will default export functions, components, pages, etc. Example: - */ - exportDefault: false -} diff --git a/src/templates/core/markdown/HookDoc.md b/src/templates/core/markdown/HookDoc.md new file mode 100644 index 0000000..b67144c --- /dev/null +++ b/src/templates/core/markdown/HookDoc.md @@ -0,0 +1,27 @@ +# ResourceName + +> My hook doc + +## Introduction + +> Describe below about your hook + +- ... + +## How to use + +> Describe below how to use your hook + +- ... + +## Examples + +> Add useful examples of code + +- ... + +```ts +// code examples + +const hookData = useResourceName() +``` diff --git a/src/templates/core/meta.yaml b/src/templates/core/meta.yaml index c3767bc..65fa9a6 100644 --- a/src/templates/core/meta.yaml +++ b/src/templates/core/meta.yaml @@ -8,26 +8,34 @@ # ⎪ AFTER READ, REMOVE THIS SECTION ⎪ # └-----------------------------------------------------------------┘ -# Component +# React Component - identifier: component folderWrapper: true resources: - - path: 'src/components' - template: './component/Component.tsx' - - path: 'src/components' - template: './component/Component.test.tsx' - - path: 'src/components' - template: './component/Component.stories.tsx' - - path: 'src/components' - template: './component/Component.styles.css' + - path: src/components + template: ./components/react-component/index.tsx + - path: src/components + template: ./components/react-component/Component.tsx + - path: src/components + template: ./components/react-component/Component.test.tsx + - path: src/components + template: ./components/react-component/Component.stories.tsx + - path: src/components + template: ./components/react-component/Component.styles.css # Async Function - identifier: async-function - resource: - path: src/utils - template: './functions/AsyncFunction.ts' - test: - path: src/utils - template: './functions/AsyncFunction.spec.ts' + resources: + - path: src/utils + template: ./functions/AsyncFunction.ts + - path: src/utils + template: ./functions/AsyncFunction.spec.ts + +# Markdown + +- identifier: hook-doc + resources: + - path: src/docs/hooks + template: ./docs/HookDoc.md diff --git a/.clingon/templates/component/Component.stories.tsx b/src/templates/core/react-component/Component.stories.tsx similarity index 100% rename from .clingon/templates/component/Component.stories.tsx rename to src/templates/core/react-component/Component.stories.tsx diff --git a/.clingon/templates/component/Component.styles.css b/src/templates/core/react-component/Component.styles.css similarity index 100% rename from .clingon/templates/component/Component.styles.css rename to src/templates/core/react-component/Component.styles.css diff --git a/.clingon/templates/component/Component.test.tsx b/src/templates/core/react-component/Component.test.tsx similarity index 100% rename from .clingon/templates/component/Component.test.tsx rename to src/templates/core/react-component/Component.test.tsx diff --git a/src/templates/core/react-component/Component.tsx b/src/templates/core/react-component/Component.tsx index e69de29..cfeec33 100644 --- a/src/templates/core/react-component/Component.tsx +++ b/src/templates/core/react-component/Component.tsx @@ -0,0 +1,13 @@ +import './ResourceName.styles.css' + +export interface ResourceNameProps { + message: string +} + +export function ResourceName({ message }: ResourceNameProps) { + return ( +
+

{message}

+
+ ) +} diff --git a/.clingon/templates/component/index.tsx b/src/templates/core/react-component/index.tsx similarity index 100% rename from .clingon/templates/component/index.tsx rename to src/templates/core/react-component/index.tsx diff --git a/src/utils/init-action.js b/src/utils/init-action.js index 41060c6..6f0a2b9 100644 --- a/src/utils/init-action.js +++ b/src/utils/init-action.js @@ -5,13 +5,18 @@ import { createFileWithContent, readFileContent } from './file.js' -import { defaultConfig } from '../templates/core/global-config.js' -import { createPresetsFolder } from './preset.js' import { checkDirectoriesTree, createDir, getLocalLibDirname } from './directory.js' +import { createPresetsFolder } from './preset.js' +import { + globalCoreFiles, + presetsCoreFiles, + templateCoreFiles +} from '../constants/init.js' +import { splitPathString } from './string.js' /* * ---------------------------------------- @@ -24,57 +29,43 @@ import { * * @returns {string | undefined} */ -export function getConfigFilePath() { - const fullPath = join(process.cwd(), 'clingon.config.json') - const fileExists = checkFileExists(fullPath) +export function getConfigFilePath(examples) { + return () => { + const fullPath = join(process.cwd(), 'clingon.config.json') + const fileExists = checkFileExists(fullPath) - if (!fileExists) return undefined + if (!fileExists) { + return { fullPath: undefined, examples } + } - return fullPath + return { fullPath, examples } + } } /** * Create the config file if it does not exist * - * @param {ReturnType} filePath + * @param {{ fullPath: string, examples: boolean }} props Props */ -export function createFileIfNotExists(filePath) { - if (filePath) { - console.info('\n✅ You already have config at: ', filePath) +export function createFileIfNotExists({ examples, fullPath }) { + if (fullPath) { + console.info('\n✅ You already have config at: ', fullPath) - return filePath + return fullPath } - const success = createFileWithContent( - 'clingon.config.json', - JSON.stringify(defaultConfig, null, 2) - ) - const fullPath = join(process.cwd(), 'clingon.config.json') + const success = createFolderAssets(globalCoreFiles, process.cwd()) if (success) { - console.info('🌎 Global config file created at: ', fullPath) + console.info( + '🌎 Global config file created at: ', + join(process.cwd(), 'clingon.config.json') + ) } else { console.error('❌ Error: Cannot create global config file, try again.') } - return filePath -} - -/** - * Get config file content - * - * @param {ReturnType} filePath Config file path - * @returns {import('../types.js').GlobalConfig | string} - */ -export function getConfigContent(filePath) { - const exists = checkFileExists(filePath) - - if (!exists) return null - - const fileContent = readFileContent(filePath) - const fileContentParsed = JSON.parse(fileContent) - - return fileContentParsed + return { fullPath, examples } } /* @@ -92,16 +83,19 @@ const presetFullDir = join(process.cwd(), dotClingonDir, presetsDir) * * @returns {boolean} */ -export function checkIfPresetFolderAlreadyExists() { - return checkDirectoriesTree([dotClingonDir, presetsDir]) +export function checkIfPresetFolderAlreadyExists(examples) { + return () => ({ + exists: checkDirectoriesTree([dotClingonDir, presetsDir]), + examples + }) } /** * Create `.clingon/prests` if not exists * - * @param {boolean} exists Folder exists? + * @param {{ exists: boolean, examples: boolean }} props Props */ -export function createPresetFolderIfNotExists(exists) { +export function createPresetFolderIfNotExists({ exists, examples }) { if (exists) { return console.info( '\n✅ You already have presets folder at: ', @@ -109,13 +103,32 @@ export function createPresetFolderIfNotExists(exists) { ) } - const created = createPresetsFolder() + exists = createPresetsFolder() - if (created) { - console.info('\n✅ Presets folder created at: ', presetFullDir) + if (exists) { + console.info('\n🎛️ Presets created at: ', presetFullDir) } else { console.error('\n❌ Error: cannot create presets dir, try again') } + + return { exists, examples } +} + +/** + * Create readme and meta file at `.clingon/templates` + * + * @param {{ exists: boolean, examples: boolean }} props Props + */ +export function createPresetsFolderAssets({ examples, exists }) { + if (!examples) return + + try { + if (!exists) throw new Error('Cannot create folder to place files') + + createFolderAssets(presetsCoreFiles, presetFullDir) + } catch (error) { + console.error(error) + } } /* @@ -129,62 +142,52 @@ const templatesFullDir = join(process.cwd(), dotClingonDir, templatesDir) /** * Check if `.clingon/templates` folder exists - * - * @returns {boolean} */ -export function checkIfTemplateFolderAlreadyExists() { - return checkDirectoriesTree([dotClingonDir, templatesDir]) +export function checkIfTemplateFolderAlreadyExists(examples) { + return () => ({ + exists: checkDirectoriesTree([dotClingonDir, templatesDir]), + examples + }) } /** * Create `.clingon/templates` if not exists * - * @param {boolean} exists Folder exists? + * @param {{ exists: boolean, examples: boolean }} props Props */ -export function createTemplateFolderIfNotExists(exists) { +export function createTemplateFolderIfNotExists({ examples, exists }) { if (exists) { console.info( '\n✅ You already have templates folder at: ', templatesFullDir ) - return exists + return { examples, exists } } - const created = createDir(templatesFullDir) + exists = createDir(templatesFullDir) - if (created) { - console.info('\n✅ Templates folder created at: ', templatesFullDir) + if (exists) { + console.info('\n📂 Templates created at: ', templatesFullDir) } else { console.error('\n❌ Error: cannot create templates dir, try again') } - return created + return { examples, exists } } /** * Create readme and meta file at `.clingon/templates` * - * @param {boolean} created Folder exists or already be created + * @param {{ exists: boolean, examples: boolean }} props Props */ -export function createTemplateFolderAssets(created) { - try { - if (!created) throw new Error() - - const localDirname = getLocalLibDirname() +export function createTemplateFolderAssets({ examples, exists }) { + if (!examples) return - const guideMdFileName = join(templatesFullDir, 'README.md') - const guideMdContent = readFileContent( - join(localDirname, 'templates', 'core', 'SCAFFOLD_GUIDE.md') - ) - - const metaFileName = join(templatesFullDir, 'meta.yaml') - const metaYamlContent = readFileContent( - join(localDirname, 'templates', 'core', 'meta.yaml') - ) + try { + if (!exists) throw new Error('Cannot create folder to place files') - createFileWithContent(guideMdFileName, guideMdContent) - createFileWithContent(metaFileName, metaYamlContent) + createFolderAssets(templateCoreFiles, templatesFullDir) } catch (error) { console.error(error) } @@ -196,8 +199,35 @@ export function createTemplateFolderAssets(created) { * ---------------------------------------- */ -export function generateExamples() { - /* Global Config */ - /* Presets */ - /* Templates */ +/** + * Create file based on json + * + * @param {{ folder: string, target: string, files: string[] }} data Data + */ +export function createFolderAssets(data, path) { + try { + const localDirname = getLocalLibDirname() + + data.forEach((item) => { + let target = join(path, item.target) + + let exists = checkDirectoriesTree(splitPathString(target)) + + if (!exists) createDir(target) + + item.files.forEach((file) => { + const fileName = join(target, file) + + const fileContent = readFileContent( + join(localDirname, item.folder, file) + ) + + return createFileWithContent(fileName, fileContent) + }) + }) + + return true + } catch (error) { + console.error(error) + } }