Skip to content

Commit

Permalink
Develop (#3)
Browse files Browse the repository at this point in the history
* chore(.gitignore): add .env

* docs(changelog): Create changelog.md file

* chore(cross-env): Install cross-env

* feat(config.json): Enable customizing path

* chore(branching): Create dev branch

* chore(CI): Create CIs

* chore(ci): test

* chore(ci): test

* chore(CI): Update package.json version

* Update version to {
  'react-component-files-generator': '1.0.8',
  npm: '9.3.1',
  node: '18.14.1',
  v8: '10.2.154.23-node.22',
  uv: '1.44.2',
  zlib: '1.2.13',
  brotli: '1.0.9',
  ares: '1.18.1',
  modules: '108',
  nghttp2: '1.51.0',
  napi: '8',
  llhttp: '6.0.10',
  uvwasi: '0.0.14',
  acorn: '8.8.1',
  simdutf: '3.1.0',
  undici: '5.19.1',
  openssl: '3.0.8+quic',
  cldr: '42.0',
  icu: '72.1',
  tz: '2022g',
  unicode: '15.0',
  ngtcp2: '0.8.1',
  nghttp3: '0.7.0'
}

* chore(CI): Update package.json version

* chore(CI): Update version to {
  'react-component-files-generator': '1.0.8',
  npm: '9.3.1',
  node: '18.14.1',
  v8: '10.2.154.23-node.22',
  uv: '1.44.2',
  zlib: '1.2.13',
  brotli: '1.0.9',
  ares: '1.18.1',
  modules: '108',
  nghttp2: '1.51.0',
  napi: '8',
  llhttp: '6.0.10',
  uvwasi: '0.0.14',
  acorn: '8.8.1',
  simdutf: '3.1.0',
  undici: '5.19.1',
  openssl: '3.0.8+quic',
  cldr: '42.0',
  icu: '72.1',
  tz: '2022g',
  unicode: '15.0',
  ngtcp2: '0.8.1',
  nghttp3: '0.7.0'
}

* chore(CI): Update package.json version

* chore(CI): Update package.json version

* chore(CI): Update package.json version

* chore(CI): Update package.json version

* chore(CI): Update package.json version

* chore(ci): enhance package version update

* chore(release): update package version [skip ci]

* ci(github-workflows): Create ci that check that the changelog has been modified

* docs(CHANGELOG): Update CHANGELOG.md

* ci(github-workflows): Apply minor change

* chore(release): update package version [skip ci]

* ci(changelog-check): Change trigger condition

* ci(workflows): change runner for ubuntu

* docs(CHANGELOG): Update changelog

* chore(release): update package version [skip ci]

---------

Co-authored-by: GitHub Actions <[email protected]>
  • Loading branch information
amine-abdelli and actions-user authored Mar 3, 2023
1 parent 431b80f commit be8fbe8
Show file tree
Hide file tree
Showing 16 changed files with 400 additions and 79 deletions.
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
NODE_ENV=development
22 changes: 22 additions & 0 deletions .github/workflows/changelog-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Changelog Check

on:
pull_request:
types: [opened, reopened, synchronize]

jobs:
changelog_check:
runs-on: ubuntu-latest
name: 🩺 Check Changelog
steps:
- uses: actions/checkout@v2
- name: Check Changelog
run: |
git fetch
echo "base ref is main checking changelog..."
if [ -z "$(git diff --name-only origin/${{ github.base_ref }} | grep CHANGELOG.md)" ]; then
echo "[FAIL] - Changelog has not been updated"
exit 1
else
echo "[SUCCESS] - Changelog has been updated"
fi
35 changes: 35 additions & 0 deletions .github/workflows/update-version.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Update package version

on:
pull_request:
types: [closed]
branches:
- develop

jobs:
update_version:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Update package version
run: |
if [[ ${{ github.ref }} == refs/heads/feat/* ]]; then
npm version minor --no-git-tag-version
else
npm version patch --no-git-tag-version
fi
- name: Commit version update
run: |
git config --global user.email "[email protected]"
git config --global user.name "amine-abdelli"
git commit -am "chore(release): update package version [skip ci]"
- name: Push changes
uses: ad-m/[email protected]
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ github.ref }}
force: true
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/node_modules
node_modules
rcfg.config.json
src
dist
yarn.lock
.yarn-integrity
.yarn-integrity
.env
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# CHANGELOG

## 1.1.3 - (03.03.2023)

_Fix_

- Fix CHANGELOG check

## 1.1.2 - (03.03.2023)

_CI_

- Check that the CHANGELOG has been well updated

## 1.1.1 - (03.03.2023)

_CI_

- Update package version based on branch name

## 1.1.0 - (07.02.2023)

_Feat_

- Create customizable path in rcfg.config.json
- Improve README.md
51 changes: 46 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
npx rcfg --init
```
![carbon](https://user-images.githubusercontent.com/77112257/205501760-78b104a0-013c-4074-baf0-10b7c98b3960.png)
#### By default, components are generated in the same folder but you can change it by editing the config file:
#### By default, components are generated in the same folder but you can customize paths by adding `"path"` props in the config file:
```
|-- /src
|-- /components
Expand All @@ -33,6 +33,7 @@

### Files generated are autofilled with generic content and the imports needed :
##### Component - (e.g. Button.component.tsx)
Imports are dynamically generated depending on files location in the file tree.
```jsx
import React from 'react';
import './Button.module.scss';
Expand Down Expand Up @@ -78,7 +79,12 @@ describe('[Component] Button', () => {

When you run --init for the first time, it will ask you a series of questions to customize the cli to your needs and will generate a "rcfg.config.json" config file.

#### Example of the **rfsb.config.json** config file:
#### Example of the **rcfg.config.json** config file:
Note that the path prop can handle this template `<%component_name%>` to dynamically create file in a folder holding the component name you're creating :

Example for a Button.component.tsx component:
```"./src/style/<%component_name%>"```
```"./src/style/Button/Button.component.tsx"```

```json
{
Expand All @@ -87,16 +93,18 @@ When you run --init for the first time, it will ask you a series of questions to
"component": {
"extension": ".tsx",
"nameExtension": ".component.tsx",
"export": "default"
"export": "default" // For component file only
},
"style": {
"extension": ".less",
"nameExtension": ".module.less",
"module": true
"module": true, // For style file only
"path": "./src/style/<%component_name%>"
},
"test": {
"extension": ".tsx",
"nameExtension": ".test.tsx"
"nameExtension": ".test.tsx",
"path": "./src/__test__/<%component_name%>"
},
"props": {
"extension": ".ts",
Expand All @@ -108,3 +116,36 @@ When you run --init for the first time, it will ask you a series of questions to
}
}
```

# Config options

### `extension` (required)
- Type: `string`
- Example value: `.js`, `.jsx`, `.ts`, `.tsx`, `.scss`, `.less`, ...
This value must start with a dot.
define ...

### `nameExtension` (required)
- Type: `string`
- Example value: `.component.tsx`, `.props.js`, `.module.css`, `null`, ...
This value must start with a dot
define ...

### `module` (optional) - For style file only
- Type: `boolean`
- Value: `true`, `false`

### `export` (optional) - For component only
// output: export { Component }; OR export default Component;
### `path` (optional) - For component only
- Type: `string`
- Example value: `./src/__test__/<%component_name%>`, `src/style`, ...
Boolean
default style
"extension" - ts tsx js jsx scss less css
"nameExtension" - e.g Button.props.ts
"path" - you can specify a path where you want to deploy. Path will be dynamically changed depending on where other elements are located.

### For style related file
"module" boolean - rather if the element is a css module or not

23 changes: 14 additions & 9 deletions lib/builder/build.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import fs from 'fs';
import { generateFullPath } from '../utils/path.utils';
import { ComponentExportTemplate, ComponentImportTemplate, ComponentNameTemplate, PropsImportTemplate, PropsTemplate, StyleImportTemplate } from '../constants';
import { sanitizeConfigPaths, sanitizePath, createDirIfNotExist, buildFile, readTemplateFile, doesConfigFileExists, log, getFullFileNames } from '../utils';
import { sanitizeConfigPaths, removeLeadingSlashes, writeFile, readTemplateFile, doesConfigFileExists, log, getFullFileNames, createFiles } from '../utils';
import { quitPrompt } from '../utils/prompt.utils';
import { componentBuildPrompt } from './prompt.build';

Expand All @@ -11,21 +12,25 @@ export async function runBuild() {
log(' Please first run the following command : rcfg --init');
quitPrompt();
}
const { name, componentEntryPoint, ...configRest } = JSON.parse(fs.readFileSync('rcfg.config.json', { encoding: 'utf8' }));
const config = JSON.parse(fs.readFileSync('rcfg.config.json', { encoding: 'utf8' }));
const { name, componentEntryPoint, ...configRest } = config;
// Clean component entry point path
const COMPONENTS_ROOT_DIR = sanitizePath(componentEntryPoint);
const COMPONENTS_ROOT_DIR = removeLeadingSlashes(componentEntryPoint);

const { chosenComponentName: ComponentName, promptResponse } = await componentBuildPrompt(configRest, componentEntryPoint);

const responsesType = promptResponse.map(({ type }) => type);
const FILE_NAMES = getFullFileNames(configRest, ComponentName);

const RELATIVE_PATH = `${COMPONENTS_ROOT_DIR}/${ComponentName}/`;
// Create all files
// We need to create files first in order to get dynamically generated imports at the right place
createFiles(config, ComponentName, responsesType);

// For each key create a file dynamically filled with template file's content
for (const [key, aConfig] of Object.entries(sanitizeConfigPaths(configRest, ComponentName))) {
const PATH_TO_CREATE_IF_NOT_EXIST = aConfig.path?.replace(ComponentNameTemplate, ComponentName) || RELATIVE_PATH;
const FILE_NAME = FILE_NAMES[key];
createDirIfNotExist(RELATIVE_PATH);

// Go to the next config if this one hasn't been picked by the user
if (!responsesType.includes(key)) continue;
Expand Down Expand Up @@ -53,7 +58,7 @@ export async function runBuild() {
.replace(new RegExp(PropsTemplate, 'g'), props);

// Build component file
buildFile(`${RELATIVE_PATH}/${FILE_NAME}`, JSON.parse(formatedTemplate));
writeFile(PATH_TO_CREATE_IF_NOT_EXIST, FILE_NAME, JSON.parse(formatedTemplate));
}
if (key === 'test') {
const COMPONENT_IMPORT_PATH = `./${FILE_NAMES['component']}`;
Expand All @@ -65,21 +70,21 @@ export async function runBuild() {
.replace(new RegExp(ComponentImportTemplate, 'g'), FULL_COMPONENT_FILE_IMPORT_STRING);

// Build test file
buildFile(`${RELATIVE_PATH}/${FILE_NAME}`, JSON.parse(formatedTemplate));
writeFile(PATH_TO_CREATE_IF_NOT_EXIST, FILE_NAME, JSON.parse(formatedTemplate));
}
if (key === 'props') {
// Dynamically replace template's tags with the right content
const formatedTemplate = JSON.stringify(readTemplateFile(key))
.replace(new RegExp(ComponentNameTemplate, 'g'), ComponentName);

// Build props file
buildFile(`${COMPONENTS_ROOT_DIR}/${ComponentName}/${FILE_NAME}`, JSON.parse(formatedTemplate));
writeFile(`${PATH_TO_CREATE_IF_NOT_EXIST}`, FILE_NAME, JSON.parse(formatedTemplate));
}
if (key === 'style') {
// Build style sheet
buildFile(`${RELATIVE_PATH}/${FILE_NAME}`, '');
writeFile(PATH_TO_CREATE_IF_NOT_EXIST, FILE_NAME, '');
}

buildFile(`${RELATIVE_PATH}/${FILE_NAME}`, '');
writeFile(PATH_TO_CREATE_IF_NOT_EXIST, FILE_NAME, '');
}
};
10 changes: 5 additions & 5 deletions lib/help/help.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
export function runHelp() {
console.log(`
Basic options:
rsfb --help / -h Show help.
rsfb --init / -i Run config initialization and creates a rcfg.config.json file.
rsfb --version / -v Output the version number.
rsfb --build / -b Build component.
rsfb --update / -u Update config.
rcfg --help / -h Show help.
rcfg --init / -i Run config initialization and creates a rcfg.config.json file.
rcfg --version / -v Output the version number.
rcfg --build / -b Build component.
rcfg --update / -u Update config.
`)
}
10 changes: 8 additions & 2 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import jsonPackage from '../package.json';

const knownOptions = ['--build', '-b', '--init', '-i', '--update', '-u', '--version', '-v', '--help', '-h'];

if(process.argv[2] === '--build' || process.argv[2] === '--b') {
if(process.argv[2] === '--build' || process.argv[2] === '-b') {
runBuild();
}
if(process.argv[2] === '--init' || process.argv[2] === '-i' || process.argv[2] === '--update' || process.argv[2] === '-u') {
Expand All @@ -27,10 +27,16 @@ if(!knownOptions.includes(process.argv[2])) {
process.exit(0);
}

// TODO: Check node version before requiring/doing anything else
// TODO : Check node version before requiring/doing anything else
// TODO : When we have no style import go one line upward'\b'
// TODO : "fill": false /* if user doesn't want his file filled up
// TODO : Trigger errors when necessary like if there is 2 files that could have the same name in the same folder in case of nameExtension missing
// TODO : Make it possible to change file name like Button.component.tsx ButtonProps.ts
// TODO : Make it possible to add pages
// TODO : Allow template in file path to be able to create a component folder
// TODO : Allow to create a component in a folder
// TODO : Parse config file and highlith errors like
// - If there is the possibility to have 2 files with the same name in the same folder.
// - If there is 2 files with the same name but in different folders WARN the user that he should add a nameExtension
// - If there is 2 dots in any extension like .component..tsx or ..tsx. or any stupid thing like that
// !: The user may be on a very old node version
4 changes: 1 addition & 3 deletions lib/init/init.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@

import { doesConfigFileExists, isReactOrNextInstalled, log } from '../utils';
import { filewalker } from '../utils/path.utils';
import { quitPrompt } from '../utils/prompt.utils';
import { checkConfigFilePrompt, triggerPromptOption } from './prompt.init';

export async function runInit() {
if (!isReactOrNextInstalled()) {
if (!isReactOrNextInstalled() && process.env.NODE_ENV !== 'development') {
return log('No React or Next.js project could be found in your dependencies, please install one of theme before going further');
}
if (doesConfigFileExists()) {
const overwriteResponse = await checkConfigFilePrompt();
if (overwriteResponse.overwrite) {
triggerPromptOption();
} else {
// TODO: Add some cool emojis :D
log('Goodbye !');
quitPrompt();
}
Expand Down
4 changes: 2 additions & 2 deletions lib/init/prompt.init.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import inquirer from 'inquirer';
import path from 'path';
import { findDependenciesFromJsonPackage, sanitizePath, writeJsonConfigFile } from '../utils';
import { findDependenciesFromJsonPackage, removeLeadingSlashes, writeJsonConfigFile } from '../utils';
import { formatResponseObjectToConfigFile } from '../utils/config.utils';
import { IPromptResponse } from '../types';

Expand Down Expand Up @@ -98,7 +98,7 @@ async function buildConfig(promptResponse: IPromptResponse) {
name: 'overwrite',
message() {
return `Here is what your component folder will look like, but you will always have the option to select only those that you need ! Does that suit you ?
./${sanitizePath(componentEntryPoint)}/
./${removeLeadingSlashes(componentEntryPoint)}/
- ${BaseComponentName}${componentFileNameExtension === 'none' ? componentFileExtension : componentFileNameExtension} (Component)
- ${BaseComponentName}.props${deductedFileExtension} (Props)
- ${BaseComponentName}${styleSheetFileSuffixExtension === 'none' ? styleSheetFileExtension : styleSheetFileSuffixExtension} (Style)
Expand Down
23 changes: 19 additions & 4 deletions lib/utils/fileSystem.utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { ComponentNameTemplate } from '../constants/template';
import fs from 'fs';
import path from 'path';
import { IConfigObject } from '../types';
import { getFullFileNames } from './config.utils';
import { log } from './log.utils';
import { sanitizeConfigPaths } from './sanitize.utils';

/**
* Create a config file filled with prompt user response
Expand Down Expand Up @@ -45,8 +48,9 @@ function createDirIfNotExist(path: string): void {
* @param path
* @param content The content we want to populate the new file with
*/
function buildFile(path: string, content: string) {
fs.writeFile(path, content, err => {
function writeFile(path: string, fileName: string, content: string) {
createDirIfNotExist(path);
fs.writeFile(`${path}/${fileName}`, content, err => {
if (err) {
console.error(err);
}
Expand Down Expand Up @@ -111,7 +115,18 @@ function doesFileExists(componentName: string, componentDir: string) {
return dir.includes(componentName)
}

function createFiles(config: IConfigObject, componentName: string, responseTypes: any[]) {
const { componentEntryPoint } = config;
for (const [key, aConfig] of Object.entries(sanitizeConfigPaths(config, componentName))) {
const FILE_NAMES = getFullFileNames(config, componentName);
const PATH_TO_CREATE_IF_NOT_EXIST = aConfig.path?.replace(ComponentNameTemplate, componentName) || `${componentEntryPoint}/${componentName}`;
const FILE_NAME = FILE_NAMES[key];
if (!responseTypes.includes(key)) continue;
writeFile(`${PATH_TO_CREATE_IF_NOT_EXIST}`, FILE_NAME, '');
}
}

export {
createDirIfNotExist, buildFile, readTemplateFile, getProjectDependencies, writeJsonConfigFile, doesConfigFileExists, isReactOrNextInstalled,
findDependenciesFromJsonPackage, doesFileExists
createDirIfNotExist, writeFile, readTemplateFile, getProjectDependencies, writeJsonConfigFile, doesConfigFileExists, isReactOrNextInstalled,
findDependenciesFromJsonPackage, doesFileExists, createFiles
};
Loading

0 comments on commit be8fbe8

Please sign in to comment.