Skip to content

Commit 1ce9985

Browse files
authored
Merge pull request #69 from akd-io/release/0.1.0
2 parents d55ff92 + b012542 commit 1ce9985

File tree

61 files changed

+994
-478
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+994
-478
lines changed

.github/workflows/publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
- name: "Install dependencies (with cache)"
2222
uses: bahmutov/npm-install@v1
2323

24-
- name: "Publish to NPM"
24+
- name: "Publish to npm"
2525
id: npmPublish
2626
uses: JS-DevTools/npm-publish@v1
2727
with:

README.md

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ npx create-next-stack
2828
Then, pick a project name, and your preferred technologies like so:
2929

3030
<p align="center">
31-
<img width="600" alt="Screenshot of Create Next Stack running in a terminal" src="assets/screenshot.png">
31+
<img width="600" alt="Screenshot of Create Next Stack running in a terminal" src="assets/screenshot.svg">
3232
</p>
3333

3434
## Supported technologies
@@ -59,7 +59,8 @@ Technologies marked as _convenience installs_ are technologies that work out of
5959
| [React](https://reactjs.org/) <img width="14" alt="required icon" src="assets/required-icon.png"> | [Docs](https://reactjs.org/docs/getting-started.html) - [GitHub repo](https://github.com/facebook/react) |
6060
| [TypeScript](https://www.typescriptlang.org/) <img width="14" alt="required icon" src="assets/required-icon.png"> | [Docs](https://www.typescriptlang.org/docs/) - [GitHub repo](https://github.com/microsoft/TypeScript) |
6161
| [ESLint](https://eslint.org/) <img width="14" alt="required icon" src="assets/required-icon.png"> | [Configuration](https://eslint.org/docs/user-guide/configuring/) - [Rules](https://eslint.org/docs/rules/) - [GitHub Repo](https://github.com/eslint/eslint) |
62-
| [Yarn](https://yarnpkg.com/) <img width="14" alt="required icon" src="assets/required-icon.png"> | [CLI Docs](https://yarnpkg.com/cli) - [GitHub repo](https://github.com/yarnpkg/berry) |
62+
| [Yarn](https://yarnpkg.com/) | [CLI Docs](https://yarnpkg.com/cli) - [GitHub repo](https://github.com/yarnpkg/berry) |
63+
| [npm](https://www.npmjs.com/) | [CLI Docs](https://docs.npmjs.com/cli/) |
6364
| [Emotion](https://emotion.sh/docs/introduction) | [Docs](https://emotion.sh/docs/introduction) - [GitHub repo](https://github.com/emotion-js/emotion) |
6465
| [styled-components](https://styled-components.com/) | [Docs](https://styled-components.com/docs) - [GitHub repo](https://github.com/styled-components/styled-components) |
6566
| [CSS Modules](https://github.com/css-modules/css-modules) | [Docs](https://github.com/css-modules/css-modules) - [Next.js-specific docs](https://nextjs.org/docs/basic-features/built-in-css-support#adding-component-level-css) |
@@ -82,9 +83,16 @@ ARGUMENTS
8283
APPNAME The name of your app, optionally including a path prefix. Eg.: "my-app" or "path/to/my-app"
8384
8485
OPTIONS
85-
-h, --help show CLI help
86-
-v, --version show CLI version
87-
--debug show verbose error messages for debugging purposes
86+
-h, --help Shows the CLI help information.
87+
-v, --version Shows the CLI version information.
88+
--debug Show verbose error messages for debugging purposes.
89+
--formatting-pre-commit-hook Adds a formatting pre-commit hook.
90+
--formik Adds Formik. (Form library)
91+
--framer-motion Adds Framer Motion. (Animation library)
92+
--package-manager=(yarn|npm) Sets the preferred package manager.
93+
--prettier Adds Prettier. (Code formatting)
94+
--react-hook-form Adds React Hook Form. (Form library)
95+
--styling=(emotion|styled-components|css-modules) Sets the preferred styling method.
8896
```
8997

9098
## License

assets/screenshot.png

-156 KB
Binary file not shown.

assets/screenshot.svg

Lines changed: 27 additions & 0 deletions
Loading

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "create-next-stack",
3-
"version": "0.0.9",
3+
"version": "0.1.0",
44
"author": "Anders Kjær Damgaard @akd-io",
55
"bin": {
66
"create-next-stack": "./bin/run"

src/create-next-stack-types.ts

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import CreateNextStack from "."
2+
import { exitWithError } from "./helpers/exit-with-error"
23
import { UnknownObject } from "./helpers/is-unknown-object"
4+
import { Writable } from "./helpers/writable"
5+
import { validateProjectPathInput } from "./questionnaire/questions/validate-project-path"
36

47
/**
58
* This function is only used to retrieve the ReturnType of a call to `createNextStackInstance.parse(CreateNextStack)`.
@@ -14,5 +17,75 @@ const temporaryWrapperForTypeSafety = () => {
1417
export type CreateNextStackParserOutput = ReturnType<
1518
typeof temporaryWrapperForTypeSafety
1619
>
20+
21+
// Unvalidated Args and Flags types
1722
export type CreateNextStackArgs = UnknownObject // Change to ParserOutput["args"] if it becomes strongly typed in the future. (Currently a normal object with any-values.)
18-
export type CreateNextStackFlags = CreateNextStackParserOutput["flags"]
23+
export type CreateNextStackFlags = Partial<CreateNextStackParserOutput["flags"]> // Change to CreateNextStackParserOutput["flags"] if it becomes strongly typed in the future. (Currently not a Partial.)
24+
25+
// Package manager flag:
26+
export const packageManagerOptions = ["yarn", "npm"] as const
27+
export type PackageManagerOption = typeof packageManagerOptions[number]
28+
export const writablePackageManagerOptions = packageManagerOptions as Writable<
29+
typeof packageManagerOptions
30+
>
31+
32+
// Styling flag:
33+
export const stylingOptions = [
34+
"emotion",
35+
"styled-components",
36+
"css-modules",
37+
] as const
38+
export type StylingOption = typeof stylingOptions[number]
39+
export const writableStylingOptions = stylingOptions as Writable<
40+
typeof stylingOptions
41+
>
42+
43+
// Valid Args type and type guard
44+
export type ValidCreateNextStackArgs = CreateNextStackArgs & { appName: string }
45+
export const validateArgs = (
46+
args: CreateNextStackArgs
47+
): args is ValidCreateNextStackArgs => {
48+
if (typeof args.appName !== "string") {
49+
exitWithError(
50+
'Outside interactive mode, you are required to specify a name for your application. Read about the "appName" argument using --help.'
51+
)
52+
process.exit() // This tells TypeScript that the throwError function exits, and lets it infer types correctly below.
53+
}
54+
55+
const appNameValidationResult = validateProjectPathInput(args.appName)
56+
57+
if (typeof appNameValidationResult === "string") {
58+
exitWithError("Invalid app name. " + appNameValidationResult)
59+
process.exit() // This tells TypeScript that the throwError function exits, and lets it infer types correctly below.
60+
}
61+
62+
return true
63+
}
64+
65+
// Valid Flags type and type guard
66+
export type ValidCreateNextStackFlags = CreateNextStackFlags & {
67+
"package-manager": PackageManagerOption
68+
styling: StylingOption
69+
}
70+
export const validateFlags = (
71+
flags: CreateNextStackFlags
72+
): flags is ValidCreateNextStackFlags => {
73+
if (flags["package-manager"] == null) {
74+
exitWithError(
75+
'Outside interactive mode, you are required to specify a package manager. Read about the "--package-manager" option using --help.'
76+
)
77+
process.exit(1)
78+
}
79+
if (flags.styling == null) {
80+
exitWithError(
81+
'Outside interactive mode, you are required to specify a styling method. Read about the "--styling" option using --help.'
82+
)
83+
process.exit(1)
84+
}
85+
return true
86+
}
87+
88+
export type ValidCNSInputs = {
89+
args: ValidCreateNextStackArgs
90+
flags: ValidCreateNextStackFlags
91+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import console from "console"
2+
import execa, { Options } from "execa"
3+
4+
export const checkFormattingLintingBuild = async (
5+
packageManager: "yarn" | "npm",
6+
runDirectory: string
7+
) => {
8+
const options: Options = {
9+
cwd: runDirectory,
10+
}
11+
12+
console.log("Checking formatting")
13+
await execa(
14+
"npx",
15+
["prettier", "--check", "--ignore-path=.gitignore", "."],
16+
options
17+
)
18+
19+
console.log("Checking linting")
20+
await execa(packageManager, ["run", "lint"], options)
21+
22+
console.log("Running build")
23+
await execa(packageManager, ["run", "build"], options)
24+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import console from "console"
2+
import { promises as fs } from "fs"
3+
import path from "path"
4+
import { v4 as uuidv4 } from "uuid"
5+
6+
export const prepareE2eTest = async (
7+
createNextStackDir: string
8+
): Promise<{
9+
pathToProdCLI: string
10+
runDirectory: string
11+
}> => {
12+
// Create unique id for this run
13+
const testRunId = uuidv4()
14+
15+
// Switch to unique test directory
16+
const runDirectory = path.resolve(
17+
`${createNextStackDir}/../create-next-stack-tests/run-${testRunId}`
18+
)
19+
await fs.mkdir(runDirectory, { recursive: true })
20+
21+
console.log(`Created test run directory at ${runDirectory}`)
22+
23+
// Run /bin/run-prod to test against compiled js files in /lib instead of ts-files in /src using ts-node.
24+
const pathToProdCLI = path.resolve(`${createNextStackDir}/bin/run-prod`)
25+
26+
console.log(`Making /bin/run readable and executable by all.`)
27+
await fs.chmod(pathToProdCLI, 0o555)
28+
29+
return {
30+
pathToProdCLI,
31+
runDirectory,
32+
}
33+
}

src/e2e/test.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,32 @@
11
import { exitWithError } from "./helpers/exit-with-error"
22
import { setGitNameAndEmail } from "./helpers/set-git-name-and-email"
3-
import { testDefaultOptions } from "./tests/default-options"
3+
import { testDefaultOptionsInteractive } from "./tests/interactive/default-options"
4+
import { testCssModulesAllFlagsNonInteractive } from "./tests/non-interactive/css-modules/css-modules-all-flags"
5+
import { testCssModulesOnlyNonInteractive } from "./tests/non-interactive/css-modules/css-modules-only"
6+
import { testEmotionAllFlagsNonInteractive } from "./tests/non-interactive/emotion/emotion-all-flags"
7+
import { testEmotionOnlyNonInteractive } from "./tests/non-interactive/emotion/emotion-only"
8+
import { testStyledComponentsAllFlagsNonInteractive } from "./tests/non-interactive/styled-components/styled-components-all-flags"
9+
import { testStyledComponentsOnlyNonInteractive } from "./tests/non-interactive/styled-components/styled-components-only"
410
;(async () => {
511
try {
612
// If not done already, Set Git name and email so `git commit` doesn't fail during create-next-app
713
await setGitNameAndEmail()
814

9-
await testDefaultOptions()
15+
// TODO: Find a way to run tests in parallel. Currently failing because simultaneous calls to `npm i -g yarn` or `npm install -g mrm@^3.0.0 mrm-task-lint-staged@^6.0.0` cause crashes.
16+
const createNextStackDir = process.cwd()
17+
18+
// Interactive test
19+
await testDefaultOptionsInteractive(createNextStackDir)
20+
21+
// Styling only
22+
await testEmotionOnlyNonInteractive(createNextStackDir)
23+
await testStyledComponentsOnlyNonInteractive(createNextStackDir)
24+
await testCssModulesOnlyNonInteractive(createNextStackDir)
25+
26+
// All flags
27+
await testEmotionAllFlagsNonInteractive(createNextStackDir)
28+
await testStyledComponentsAllFlagsNonInteractive(createNextStackDir)
29+
await testCssModulesAllFlagsNonInteractive(createNextStackDir)
1030
} catch (error) {
1131
exitWithError(error)
1232
}

src/e2e/tests/default-options.ts

Lines changed: 0 additions & 47 deletions
This file was deleted.

0 commit comments

Comments
 (0)