Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add package generator for basics/composites/plugins #503

Merged
merged 2 commits into from
Jun 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "launch generator",
"type": "node",
"request": "launch",
"skipFiles": ["<node_internals>/**"],
"program": "${workspaceFolder}/script/generator/src/index.js",
"console": "integratedTerminal"
}
]
}
24 changes: 24 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,30 @@ a single module, you can specify that one specifically
(ex. `localStorage.debug = 'flyte:adminEntity'` to only see decoded Flyte
Admin API requests).

## Generate new package

To add a new package use a script

```bash
yarn generate:package
```

After new package is generated, you will need to update some values to be able to use it with other packages.
For example in case if package plan to be used in `console` app

Ensure to add proper webpack alias path resolutions into:
* ./storybook/main.js - as `'@flyteconsole/flyte-api': path.resolve(__dirname, '../packages/plugins/flyte-api/src’),`
* packages/zapp/console/webpack.common.config.ts to alias section - as `'@flyteconsole/flyte-api': path.resolve(__dirname, '../packages/plugins/flyte-api/src’),`

To add child package usage to other package, in parent package ->
* Add `{ "path": “../../${type}/${package-name}" }` to tsconfig.json
* Add `{ "path": “../../${type}/${package-name}/tsconfig.build.json" }` to tsconfig.build.json (if exists)
- Then you can import your changes as `import { getLoginUrl } from '@flyteconsole/flyte-api’;`

> If you see `yarn lint` package not defined issues update `.\eslintrc.js` by adding your package to
'import/core-modules': ['@clients/locale', '@clients/primitives', '@clients/theme'],


## Storybook

This project has support for [Storybook](https://storybook.js.org/).
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@
"packages/basics/**",
"packages/composites/**",
"packages/plugins/**",
"packages/zapp/**"
"packages/zapp/**",
"script/generator/**"
],
"scripts": {
"clean": "yarn workspace @flyteconsole/client-app clean",
"start": "yarn workspace @flyteconsole/client-app start",
"start:prod": "yarn workspace @flyteconsole/client-app start:prod",
"build:prod": "yarn workspace @flyteconsole/client-app build:prod",
"build:storybook": "build-storybook",
"generate:package": "yarn workspace @flyteconsole/generator start",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
"storybook": "start-storybook -p 6006",
"test": "NODE_ENV=test jest",
Expand Down
10 changes: 10 additions & 0 deletions script/generator/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* Note: at the time of creation, eslint.cjs files are recommended for "type":"module" projects.
* https://eslint.org/docs/user-guide/configuring/configuration-files
*/
module.exports = {
rules: {
'no-console': 'off',
'import/no-extraneous-dependencies': 'off',
},
};
20 changes: 20 additions & 0 deletions script/generator/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "@flyteconsole/generator",
"version": "1.0.0",
"exports": "./src/index.js",
"license": "MIT",
"private": true,
"type": "module",
"node": ">=17.6.0",
"scripts": {
"start": "yarn install && ./src/index.js"
},
"dependencies": {},
"devDependencies": {
"eslint": "^8.15.0",
"chalk": "^5.0.1",
"inquirer": "^8.2.4",
"listr": "^0.14.3",
"ncp": "^2.0.0"
}
}
7 changes: 7 additions & 0 deletions script/generator/src/cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import askQuestions from './questions.js';
import createProject from './main.js';

export async function cli() {
const options = await askQuestions();
createProject(options);
}
29 changes: 29 additions & 0 deletions script/generator/src/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import path from 'path';
import { fileURLToPath } from 'url';

// eslint-disable-next-line no-underscore-dangle
const __filename = fileURLToPath(import.meta.url);

// eslint-disable-next-line no-underscore-dangle
const __dirname = path.dirname(__filename);

export const projectTypeSoSettingsMap = {
basics: {
packagePartialPath: 'packages/basics/',
targetDirectoryPartialPath: path.resolve(__dirname, '../../../packages/basics/'),
// using the same template for basics, components and microapps for now
templateDirectory: path.resolve(__dirname, '../templates', 'basics'),
},
composites: {
packagePartialPath: 'packages/composites/',
targetDirectoryPartialPath: path.resolve(__dirname, '../../../packages/composites/'),
// using the same template for basics, components and microapps for now
templateDirectory: path.resolve(__dirname, '../templates', 'basics'),
},
plugins: {
packagePartialPath: 'packages/plugins/',
targetDirectoryPartialPath: path.resolve(__dirname, '../../../packages/plugins/'),
// using the same template for basics, components and microapps for now
templateDirectory: path.resolve(__dirname, '../templates', 'basics'),
},
};
4 changes: 4 additions & 0 deletions script/generator/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env node
import { cli } from './cli.js';

cli();
35 changes: 35 additions & 0 deletions script/generator/src/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import chalk from 'chalk';
import ncp from 'ncp';
import { promisify } from 'util';
import Listr from 'listr';
import { editPackageJSON } from './utils.js';

const copy = promisify(ncp);

async function copyTemplateFiles(options) {
return copy(options.templateDirectory, options.targetDirectory, {
clobber: false, // if set to false, ncp will not overwrite destination files that already exist
});
}

async function createProject(config) {
const tasks = new Listr([
{
title: 'Copy template files',
task: async () => copyTemplateFiles(config),
},
{
title: 'Update package.json',
task: async () => editPackageJSON(config),
enabled: () => true,
},
]);

await tasks.run();

console.log(`${chalk.green.bold('DONE')}. Project ready`);

return true;
}

export default createProject;
110 changes: 110 additions & 0 deletions script/generator/src/questions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import path from 'path';
import chalk from 'chalk';
import inquirer from 'inquirer';
import { checkPathExists } from './utils.js';
import { projectTypeSoSettingsMap } from './constants.js';

const askQuestions = async () => {
console.log(
chalk.hex('#e7c99a')('Use the up and down arrow keys to navigate multi-choice questions'),
);

const questionsSetProjectType = [
{
name: 'type',
type: 'list',
message: 'Please choose a project type to use: ',
choices: [
{
name: 'Basic',
value: 'basics',
},
{
name: 'Composite',
value: 'composites',
},
{
name: 'Plugin',
value: 'plugins',
},
],
default: 'composites',
},
];

/* Initial set of questions */
const getQuestionsSetFolderName = (templateDirectory, targetDirectory) => [
{
name: 'name',
type: 'input',
message: 'Project name(folder): ',
validate: (projectName) => {
let valid = true;

/* Reg ex to ensure that project name starts with a letter, includes letters, numbers, underscores and hashes */
if (/^[a-z]*-?[a-z]*$/gm.test(projectName)) {
valid = valid && true;
} else {
return 'Project must \n 1) start with a letter \n 2) name may only include letters, numbers, underscores and hashes.';
}

/* Check that no folder exists at this location */
if (!checkPathExists(templateDirectory)) {
return 'Could not find a template for your selected choice';
}

/* Check that no folder exists at this location */
if (checkPathExists(path.resolve(targetDirectory, projectName))) {
return 'Project with this name already exists at this location';
}

return valid && true;
},
},
{
name: 'description',
type: 'input',
message: 'Project description: ',
},
];

try {
/* Actually ask the questions */
const answersA = await inquirer.prompt(questionsSetProjectType);

const projectType = answersA.type;

const { targetDirectoryPartialPath, templateDirectory, packagePartialPath } =
projectTypeSoSettingsMap[projectType];

const questionsB = getQuestionsSetFolderName(templateDirectory, targetDirectoryPartialPath);
const answersB = await inquirer.prompt(questionsB);

const projectName = answersB.name;

/* Collate answers */
const answers = {
...answersA,
...answersB,
templateDirectory,
targetDirectory: path.resolve(targetDirectoryPartialPath, projectName),
testPath: path.join(packagePartialPath, projectName),
};

return answers;
} catch (err) {
if (err) {
switch (err.status) {
case 401:
console.error('401');
break;
default:
console.error(err);
}
}
}

return {};
};

export default askQuestions;
40 changes: 40 additions & 0 deletions script/generator/src/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import fs from 'fs';

const checkPathExists = (pathToCheck) => {
try {
return fs.existsSync(pathToCheck);
} catch (err) {
console.error(err);
}

return false;
};

async function editPackageJSON(options) {
const targetDir = options.targetDirectory;
let jsonFile;

await fs.readFile(`${targetDir}/package.json`, (err, data) => {
/* If no package.json, this will be skipped */
if (!err) {
jsonFile = JSON.parse(data);
jsonFile.name = `@flyteconsole/${options.name}`;
jsonFile.description = options.description;

jsonFile.scripts.test = jsonFile.scripts.test.replace('folder-path', options.testPath);

fs.writeFile(`${targetDir}/package.json`, JSON.stringify(jsonFile, null, '\t'), (err2) => {
if (err2) {
throw new Error('Unable to update package.json');
}
});
}
});
}

const mapToTemplates = {
'Node-Express-Mongo-JS': 'jemn',
'HTML,CSS,JS': 'basic',
};

export { checkPathExists, mapToTemplates, editPackageJSON };
7 changes: 7 additions & 0 deletions script/generator/templates/basics/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
// eslint-disable-next-line import/no-unresolved
const sharedConfig = require('../../../script/test/jest.base.js');

module.exports = {
...sharedConfig,
};
25 changes: 25 additions & 0 deletions script/generator/templates/basics/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "placeholder",
"version": "0.1.0",
"description": "Your description here",
"main": "./dist/index.js",
"module": "./lib/esm/index.js",
"types": "./lib/esm/index.d.ts",
"private": false,
"scripts": {
"build": "yarn build:esm && yarn build:cjs",
"build:esm": "tsc --module esnext --outDir lib/esm",
"build:cjs": "tsc",
"test": "NODE_ENV=test jest"
},
"peerDependencies": {
"react": "^16.13.1",
"react-dom": "^16.13.1"
},
"devDependencies": {
"@types/react": "^16.9.34",
"@types/react-dom": "^16.9.7",
"react": "^16.13.1",
"react-dom": "^16.13.1"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import * as React from 'react';

export const SampleComponent = (): React.ReactElement => {
return <div>It&apos;s me - Navigation Bar</div>;
};

export const add = (a: number, b: number) => {
return a + b;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';

import { SampleComponent } from '.';

export default {
title: 'Primitives/NavBar',
component: SampleComponent,
} as ComponentMeta<typeof SampleComponent>;

export const Primary: ComponentStory<typeof SampleComponent> = () => {
return <SampleComponent />;
};

const Template: ComponentStory<typeof SampleComponent> = () => <SampleComponent />;
export const Secondary = Template.bind({});
Loading