Skip to content

Commit

Permalink
feat: implementing init command #wip
Browse files Browse the repository at this point in the history
  • Loading branch information
ipetinate committed May 15, 2024
1 parent e4b9100 commit 307de63
Show file tree
Hide file tree
Showing 12 changed files with 297 additions and 120 deletions.
2 changes: 1 addition & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
"semi": false,
"tabWidth": 2,
"singleQuote": true,
"printWidth": 100,
"printWidth": 80,
"trailingComma": "none"
}
6 changes: 6 additions & 0 deletions clingon.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"alias": {
"src": "@"
},
"exportDefault": false
}
1 change: 0 additions & 1 deletion clingon.json

This file was deleted.

14 changes: 11 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
},
"dependencies": {
"@inquirer/prompts": "^4.3.2",
"commander": "^12.0.0"
"commander": "^12.0.0",
"rxjs": "^7.8.1"
},
"devDependencies": {
"@rollup/plugin-babel": "^6.0.4",
Expand Down
27 changes: 23 additions & 4 deletions src/actions/init.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,31 @@
import { globalConfigSubject } from '../store/global.js'

import { compose } from '../utils/compose.js'
import { readFileContent } from '../utils/file.js'
import { getConfigContent, getFilePathOrCreate } from '../utils/init-action.js'
import {
createFileIfNotExists,
getConfigContent,
getConfigFilePath,
updateGlobalStore
} from '../utils/init-action.js'

export async function initAction() {
// TODO: generate clingon.config.js
let alreadyHaveGlobalConfig = false

const subscription = globalConfigSubject.subscribe((content) => {
if (typeof content === 'object') alreadyHaveGlobalConfig = true
})

const result = compose(getFilePathOrCreate, getConfigContent)
if (!alreadyHaveGlobalConfig) {
compose(
getConfigFilePath,
createFileIfNotExists,
getConfigContent,
updateGlobalStore
)
}

// TODO: create folders for presets and templates
// TODO: add a default template for function or other asset

return subscription.unsubscribe()
}
150 changes: 92 additions & 58 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,34 @@ import { initAction } from './actions/init.js'
import { guidedAction } from './actions/guided.js'
import { createAction } from './actions/create.js'

import { getLocalLibDirname } from './utils/directory.js'
import { TestFrameworkEnum } from './enums/frameworks.js'
import { getLocalLibDirname } from './utils/directory.js'
import { globalConfigSubject } from './store/global.js'

/*
* Global Variables
*/

export const localDirname = getLocalLibDirname()
export let globalConfig = null

/*
* Subscriptions
*/

const globalConfigSubscription = globalConfigSubject.subscribe(
(globalConfigContent) => {
if (typeof globalConfigContent !== 'object') return

globalConfig = globalConfigContent
}
)

/*
* Unsubscriptions
*/

process.on('exit', globalConfigSubscription.unsubscribe)

/*
* Resources
Expand All @@ -26,81 +46,95 @@ const program = new Command()
*/

program
.name('clingon')
.description('CLI to generate files based on templates')
.version('0.9.0', '-v, --version', 'Current version')
.name('clingon')
.description('CLI to generate files based on templates')
.version('0.9.0', '-v, --version', 'Current version')

/*
* Guided flow - generate components based on prompt answers
*/

program
.command('gen')
.argument('[name]', 'Resource name')
.action(guidedAction)
.description('Start a guided flow to generate resources (components, functions, pages, etc)')
.command('gen')
.argument('[name]', 'Resource name')
.action(guidedAction)
.description(
'Start a guided flow to generate resources (components, functions, pages, etc)'
)

/*
* Preset flow - create instantly resources with presets
*/

program
.command('create')
.argument('<name>', 'Resource name')
.option('--preset [preset]', 'Preset name')
.option('--type <resourceType>', 'Resource type: "function" | "page" | "component"')
.option('--vue-version [vueVersion]', 'Vue version: "2" | "3" (default: 3))', '3')
.option('--framework <frameworkName>', 'Framework name for default preset: vue or react')
.option(
'--css-framework [cssFramework]',
'Style approach: "css_modules" | "tailwind_inline" | "tailwind_file" | "css_vanilla" | "scss" (default: no_style)',
'no_style'
)
.option(
'--test-framework [testFrameworkName]',
'Test framework: jest or vitest (default: vitest)',
TestFrameworkEnum.vitest
)
.option(
'--path <resourcePath>',
'Path to resource, use dot (".") to current dir where command is executed'
)
.option(
'--test-path [testPath]',
'Path to test, use dot (".") to current dir where command is executed, if ommited, and --spec is present, will use the same path to resource'
)
.option(
'--story-path [storyPath]',
'Path to story, use dot (".") to current dir where command is executed, if ommited, and --spec is present, will use the same path to resource'
)
.option('--typescript', 'With TypeScript (default: false)', false)
.option('--testing-library', 'With Testing Library (default: false)', false)
.option('--test', 'Add test file (default: false)', false)
.option('--spec', 'Add spec file (default: false)', false)
.option('--story', 'Add story file (default: false)', false)
.option(
'--folder-wrapper',
'Creates a folder with the name of the resource, with the files inside it',
false
)
.action(createAction)
.usage('create <resourceName> --preset <presetName>')
.usage(
'create <resourceName> --type (component | page | function) --framework <framework> (--test | --spec) --typescript --folder-wrapper --story --test-framework (vitest | jest)'
)
.description(
'Creates the resources with a local preset in non-verbose mode (preview and ask to confirm are not shown, resources will be created immediately), if the preset folder is empty, it will call the guided flow (the same as the `gen` command executes)'
)
.command('create')
.argument('<name>', 'Resource name')
.option('--preset [preset]', 'Preset name')
.option(
'--type <resourceType>',
'Resource type: "function" | "page" | "component"'
)
.option(
'--vue-version [vueVersion]',
'Vue version: "2" | "3" (default: 3))',
'3'
)
.option(
'--framework <frameworkName>',
'Framework name for default preset: vue or react'
)
.option(
'--css-framework [cssFramework]',
'Style approach: "css_modules" | "tailwind_inline" | "tailwind_file" | "css_vanilla" | "scss" (default: no_style)',
'no_style'
)
.option(
'--test-framework [testFrameworkName]',
'Test framework: jest or vitest (default: vitest)',
TestFrameworkEnum.vitest
)
.option(
'--path <resourcePath>',
'Path to resource, use dot (".") to current dir where command is executed'
)
.option(
'--test-path [testPath]',
'Path to test, use dot (".") to current dir where command is executed, if ommited, and --spec is present, will use the same path to resource'
)
.option(
'--story-path [storyPath]',
'Path to story, use dot (".") to current dir where command is executed, if ommited, and --spec is present, will use the same path to resource'
)
.option('--typescript', 'With TypeScript (default: false)', false)
.option('--testing-library', 'With Testing Library (default: false)', false)
.option('--test', 'Add test file (default: false)', false)
.option('--spec', 'Add spec file (default: false)', false)
.option('--story', 'Add story file (default: false)', false)
.option(
'--folder-wrapper',
'Creates a folder with the name of the resource, with the files inside it',
false
)
.action(createAction)
.usage('create <resourceName> --preset <presetName>')
.usage(
'create <resourceName> --type (component | page | function) --framework <framework> (--test | --spec) --typescript --folder-wrapper --story --test-framework (vitest | jest)'
)
.description(
'Creates the resources with a local preset in non-verbose mode (preview and ask to confirm are not shown, resources will be created immediately), if the preset folder is empty, it will call the guided flow (the same as the `gen` command executes)'
)

/*
* Init tool assets, generate clingon.config.json
*/

program
.command('init')
.action(initAction)
.usage('init')
.description('Init all needed setup, generate files and create folders to store assets.')
.command('init')
.action(initAction)
.usage('init')
.description(
'Init all needed setup, generate files and create folders to store assets.'
)

/*
* Parse program to execution
Expand Down
7 changes: 7 additions & 0 deletions src/store/global.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { join } from 'node:path'
import { BehaviorSubject } from 'rxjs'
import { getConfigContent } from '../utils/init-action.js'

const configFilePath = join(process.cwd(), 'clingon.config.json')

export const globalConfigSubject = new BehaviorSubject(getConfigContent(configFilePath))
69 changes: 38 additions & 31 deletions src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,42 +23,49 @@ import { StoryPostfixEnum, TestPostfixEnum, StylePostfixEnum } from 'enums/postf
* @typedef {TestPostfix | StoryPostfix | StylePostfix} Postfix - All files postfixes
*
* @typedef {{
* name: string;
* type: Resource;
* framework: Framework;
* version: string | number
* typescript: boolean;
* withTest: boolean;
* withStory: boolean;
* withTestingLibrary: boolean
* folderWrapper: boolean
* testPostfix: TestPostfix;
* storyPostfix: StoryPostfix;
* testFramework: TestFramework
* cssFramework: CssFramework
* resourcePath: string;
* testPath: string
* storyPath: string
* name: string;
* type: Resource;
* framework: Framework;
* version: string | number
* typescript: boolean;
* withTest: boolean;
* withStory: boolean;
* withTestingLibrary: boolean
* folderWrapper: boolean
* testPostfix: TestPostfix;
* storyPostfix: StoryPostfix;
* testFramework: TestFramework
* cssFramework: CssFramework
* resourcePath: string;
* testPath: string
* storyPath: string
* }} Answers - Users prompted answers
*
* @typedef {{
* preset: string,
* type: Resource,
* framework: Framework,
* testFramework: TestFramework,
* cssFramework: CssFramework
* path: string,
* testPath: string,
* storyPath: string,
* test: boolean,
* spec: boolean,
* story: boolean,
* typescript: boolean,
* testingLibrary: boolean,
* folderWrapper: boolean,
* vueVersion: VueVersion
* preset: string,
* type: Resource,
* framework: Framework,
* testFramework: TestFramework,
* cssFramework: CssFramework
* path: string,
* testPath: string,
* storyPath: string,
* test: boolean,
* spec: boolean,
* story: boolean,
* typescript: boolean,
* testingLibrary: boolean,
* folderWrapper: boolean,
* vueVersion: VueVersion
* }} CommanderOptions - Commander command line options
*
* @typedef {{
* alias: {
* src: string
* },
* exportDefault: boolean
* }} GlobalConfig - Clingon global config object
*
* @typedef {"Page" | "Component" | "Function" | "Type" | "Model" | "Enum" | "Test" | "Spec" | "Cypress Spec" | "Storybook Story"} TypeNames - Resource type names
*
* @typedef {"Vue" | "React" | "Vanilla"} FrameworkNames - Framework names
Expand Down
13 changes: 11 additions & 2 deletions src/utils/file.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,16 @@ export function createFileWithContent(filename, content) {

/**
* Check if file exists
* @param {string} path File path
*
* @param {string} fullPath File path
* @returns {boolean}
*/
export function checkFileExists(path) {}
export function checkFileExists(fullPath) {
try {
fs.accessSync(fullPath, fs.constants.F_OK)

return true
} catch {
return false
}
}
Loading

0 comments on commit 307de63

Please sign in to comment.