Skip to content
This repository has been archived by the owner on Feb 5, 2022. It is now read-only.

Commit

Permalink
feat: SAO v2 (#145)
Browse files Browse the repository at this point in the history
BREAKING CHANGE:

see changelog
  • Loading branch information
egoist authored Jul 27, 2020
1 parent d6df763 commit ca204d1
Show file tree
Hide file tree
Showing 74 changed files with 6,296 additions and 7,398 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false
trim_trailing_whitespace = false
4 changes: 4 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
dist
rollup.config.js
scripts
docs/typedoc/
26 changes: 26 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
env: {
node: true,
},
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended',
],
rules: {
'@typescript-eslint/member-delimiter-style': [
'error',
{
multiline: {
delimiter: 'none',
},
},
],
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/camelcase': 'off',
'@typescript-eslint/ban-ts-ignore': 'off'
},
}
2 changes: 1 addition & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1 +1 @@
* text=auto
* text=auto eol=lf
39 changes: 39 additions & 0 deletions .github/workflows/node-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions

name: Node.js CI

on:
push:
branches: [master]
pull_request:
branches: [master]

jobs:
test:
name: Test on ${{ matrix.os }}
runs-on: ${{ matrix.os }}

strategy:
matrix:
node-version: [12.x]
os: [windows-latest]

steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/cache@v2
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- run: yarn
- run: yarn test
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
node_modules
*.log
dist
.DS_Store
out/
docs/typedoc/
59 changes: 0 additions & 59 deletions bin/cli.js

This file was deleted.

3 changes: 0 additions & 3 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,3 @@ jobs:
- run:
name: test
command: yarn test
- run:
name: Release
command: yarn semantic-release
5 changes: 5 additions & 0 deletions cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env node
/* eslint-disable */
const { runCLI, handleError } = require('.')

runCLI().catch(handleError)
124 changes: 124 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
## Basic Usage

```bash
sao nm my-project
```

Running this command will download the generator from npm ([sao-nm](npm.im/sao-nm)) and generate a new project to `./my-project` directory.

You can also use any GitHub repo:

```bash
sao egoist/graphql-api-starter new-project
```

When the generator does not include a file called `saofile.js`, SAO will simply copy it to output directory. In this case it works kinda like `git clone` but without git history and the generator will be cached locally.

## Authoring Generators

Starting by creating a new folder, let's call it `sao-npm` because we want to use it to scaffold out a npm package. Then create a `saofile.js` inside the folder:

```js
module.exports = {
prompts: [
{
type: 'input',
name: 'name',
message: 'What is the name of this package',
},
{
type: 'input',
name: 'description',
message: 'How would you describe this package',
},
],
actions: [
{
type: 'add',
files: '**',
},
],
}
```

Here we use `prompts` to ask users some questions and retrieve answers as an object which looks like `{ name: '..', description: '...' }`.

Next we use `actions` to define a series of actions, the `add` action will copy `files` from `sao-npm/template/` to the output directory.

Now let's create some template files, for example, `template/package.json`:

```json
{
"name": "<%= name %>",
"description": "<%= description %>",
"version": "0.0.0"
}
```

Template files supports [ejs](https://ejs.co) template engine, and the anwers we retrieved will be available here as local variable.

### Prompts

`prompts` is a list of questions you want the user to answer.

Each `prompt` object has a `type` property, which can be either:

- `"input" | "invisible" | "list" | "password" | "text"`: [StringPromptOptions](/typedoc/interfaces/stringpromptoptions.html)
- `"confirm"`: [BooleanPromptOptions](/typedoc/interfaces/booleanpromptoptions.html)
- `"autocomplete" | "editable" | "form" | "multiselect" | "select" | "survey" | "list" | "scale"`: [ArrayPromptOptions](/typedoc/interfaces/arraypromptoptions.html)

Check out the [GeneratorConfig['prompts']](/typedoc/interfaces/generatorconfig.html#prompts) type for details.

## Testing Generators

Using the testing framework [Jest](https://jestjs.io/) as example:

```js
import { SAO } from 'sao'

test('it works', () => {
const sao = new SAO({
generator: '/absolute/path/to/your/generator',
// `mock` make SAO run in mock mode
// then it will use default value for prompts
// It defaults to `process.env.NODE_ENV === 'test'`
// if it's not specified explicitly
mock: true
})

await sao.run()

expect(sao.answers).toEqual({
answerA: true,
answerB: 'foo'
})
expect(await sao.getOutputFiles()).toEqual([
'a.js',
'b.js'
])
expect(await sao.readOutputFile('foo.js')).toBe(`const foo = 'foo'`)
})
```

Setting the option `mock` to `true` or setting `process.env.NODE_ENV` to `test` will make SAO run in mock mode:

- All prompts will use default value instead of asking user for input, you can also pass a custom `answers` object if you want.
- Use mocked value for git user information.
- Logger won't output text to terminal, instead they're saved to `sao.logger.lines`
- `outDir` will be a random temporary directory.

### Testing Prompts

By setting `mock: true` you are essentially making all prompts use their default values, however you can provide custom `answers`:

```js
const sao = new SAO({
generator: '/absolute/path/to/your/generator',
mock: true,
answers: {
unitTest: true,
},
})
```

With above code you can test if you generator works properly when the answer of `unitTest` is `true`
55 changes: 55 additions & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"
/>
<title>SAO - Futuristic Scaffolding Tool</title>
<!-- Stylesheet -->
<link
rel="stylesheet"
href="https://unpkg.com/@egoist/docup@1/dist/docup.min.css"
/>
<style>
:root {
--bg: #131415;
--fg: #eaeaea;
--navbar-bg: var(--bg);
--sidebar-bg: var(--bg);
--sidebar-text-fg: var(--fg);
--code-block-bg: #1a1a1a;
--code-span-bg: #1a1a1a;
--navlink-hover-bg: rgba(103, 103, 103, 0.29);
--sidebar-menu-item-active-fg: white;
--content-link-fg: #ffe77a;
}
body {
background: var(--bg);
color: var(--fg);
}
</style>
</head>
<body>
<!-- Script -->
<script src="https://unpkg.com/@egoist/docup@1/dist/docup.min.js"></script>
<!-- Start app -->
<script>
docup.init({
title: 'SAO',
navLinks: [
{
text: 'TypeDoc',
link: '/typedoc/'
},
{
text: 'GitHub',
link: 'https://github.com/saojs/sao'
}
]
})
</script>
</body>
</html>
9 changes: 9 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = {
testEnvironment: 'node',
transform: {
'^.+\\.tsx?$': 'ts-jest'
},
testRegex: '(/__test__/.*|(\\.|/)(test|spec))\\.tsx?$',
testPathIgnorePatterns: ['/node_modules/', '/dist/', '/types/', '/out/', '/fixtures/'],
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node']
}
Loading

0 comments on commit ca204d1

Please sign in to comment.