1
0
mirror of synced 2026-02-03 18:01:02 -05:00

Compare commits

...

133 Commits

Author SHA1 Message Date
Blitz.js Bot
fa6e96731a (meta) updated @iojcde contributions 2022-07-25 08:36:58 -04:00
Blitz.js Bot
f59dfda878 (meta) added @iojcde as contributor 2022-07-22 10:43:55 -04:00
Blitz.js Bot
e15c62a8d8 (meta) added @SerekKiri as contributor 2022-07-20 02:12:31 -04:00
Blitz.js Bot
f97c123ddb (meta) updated @the-bayer contributions 2022-07-14 06:11:38 -04:00
Blitz.js Bot
7fd287f004 (meta) updated @Zeko369 contributions 2022-07-12 08:41:32 -04:00
Blitz.js Bot
f0bbdf561d (meta) added @Trancever as contributor 2022-07-11 05:35:13 -04:00
Brandon Bayer
a9c6bcc63f Update CODEOWNERS 2022-07-05 18:06:07 +02:00
Blitz.js Bot
e1fc695d24 (meta) updated @datner contributions 2022-06-30 05:05:37 -04:00
Blitz.js Bot
525e436b9d (meta) added @sergous as contributor 2022-06-20 07:19:40 -04:00
Blitz.js Bot
a98f972bef (meta) added @remlse as contributor 2022-06-20 06:50:14 -04:00
Blitz.js Bot
1c2fdfee37 (meta) added @datner as contributor 2022-06-19 12:13:48 -04:00
Blitz.js Bot
8102086400 (meta) added @jakedee as contributor 2022-06-19 08:49:58 -04:00
Blitz.js Bot
0366729a95 (meta) updated @andreasasprou contributions 2022-06-13 11:07:46 -04:00
Blitz.js Bot
352d2af366 (meta) added @iDavidB as contributor 2022-06-08 17:50:05 -04:00
Blitz.js Bot
9b8c4039f0 (meta) added @webdeb as contributor 2022-06-07 13:09:03 -04:00
Blitz.js Bot
262b647855 (meta) added @minho42 as contributor 2022-06-07 13:05:48 -04:00
Min ho Kim
03017046f7 Fix typos in docs (#3395)
(ignore)
2022-06-07 10:05:43 -07:00
Blitz.js Bot
28d2671ddb (meta) added @paulm17 as contributor 2022-06-07 13:02:32 -04:00
Blitz.js Bot
86da1612da (meta) added @rmassie as contributor 2022-06-07 12:59:17 -04:00
Blake Bayer
919465c9b6 Add try/catch in change password mutation (#3337)
* Revert "Update change password w/ try/catch"

This reverts commit 186532ef2d.

* Update changePassword.ts

* Update packages/generator/templates/app/app/auth/mutations/changePassword.ts

Co-authored-by: Aleksandra <alexsandra.sikora@gmail.com>

* Update changePassword.ts

* Apply suggestions from code review

Co-authored-by: Aleksandra <alexsandra.sikora@gmail.com>
2022-05-10 11:27:13 +02:00
Blitz.js Bot
b84ed74496 (meta) updated @ganeshmani contributions 2022-05-08 08:44:55 -04:00
Blitz.js Bot
dc86c78bd1 (meta) added @the-bayer as contributor 2022-04-29 08:31:27 -04:00
Blake Bayer
45b38cc836 Revert "Update change password w/ try/catch" (#3323)
This reverts commit 186532ef2d.
2022-04-29 14:31:23 +02:00
the-bayer
186532ef2d Update change password w/ try/catch 2022-04-27 11:30:25 -04:00
Blitz.js Bot
77858c5558 (meta) updated @dillonraphael contributions 2022-04-15 08:35:51 -04:00
Aleksandra
e9a98ffe3d bump recipe/example versions (ignore) 2022-04-12 12:46:49 +02:00
Aleksandra
2c06dd6f18 v0.45.4 2022-04-12 12:45:36 +02:00
Aleksandra
881d686233 Upgradereact and @types/react in new app templates, update types (#3282)
(newapp)
2022-04-12 12:38:49 +02:00
Blitz.js Bot
a7deaafbc7 (meta) updated @dillonraphael contributions 2022-04-07 12:46:42 -04:00
Blitz.js Bot
7c698f0b35 (meta) added @Caslus as contributor 2022-04-04 04:45:50 -04:00
Blitz.js Bot
09a8c94392 (meta) added @timfee as contributor 2022-04-04 04:36:59 -04:00
Tim Feeley
35b9ded76e Fix typo in recipe step name (#3265)
(ignore)
2022-04-04 10:36:54 +02:00
Blitz.js Bot
85c10b9d3f (meta) added @davidbarker as contributor 2022-04-04 04:20:49 -04:00
Blitz.js Bot
2675942c58 (meta) added @jscyo as contributor 2022-03-28 05:59:31 -04:00
Aleksandra
b3ad310f6f Add JDLT to sponsors list (#3226)
(meta)
2022-03-10 10:20:09 -05:00
Blitz.js Bot
d41385b592 (meta) added @numanaral as contributor 2022-03-06 14:37:25 -05:00
Husnul Jahneer
dfbab3919d Add @husnuljahneer as L1 Maintainer (#3142)
(meta)
2022-02-28 10:50:13 -05:00
Blitz.js Bot
e5c607164e (meta) added @eai04191 as contributor 2022-02-24 19:20:19 -05:00
John Vandivier
49d1e91a64 don't suggest faker.js in code comments (#3178)
(newapp)
2022-02-23 10:09:58 +01:00
Blitz.js Bot
19ea640705 (meta) added @Lokprakash-babu as contributor 2022-02-23 03:03:14 -05:00
Brandon Bayer
f2d814813f (newapp) change preview-email to just in time import so it doesn't need to be in production deps 2022-02-17 11:29:31 -05:00
dependabot[bot]
f99ebf5f37 Bump superjson from 1.7.5 to 1.8.1 in /nextjs (#3165)
Bumps [superjson](https://github.com/blitz-js/superjson) from 1.7.5 to 1.8.1.
- [Release notes](https://github.com/blitz-js/superjson/releases)
- [Commits](https://github.com/blitz-js/superjson/compare/v1.7.5...v1.8.1)

---
updated-dependencies:
- dependency-name: superjson
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-11 12:43:41 +01:00
Aleksandra
ef2c0cdd67 bump recipe/example versions (ignore) 2022-02-09 17:07:08 +01:00
Aleksandra
d658af7407 v0.45.3 2022-02-09 17:05:40 +01:00
Brandon Bayer
0f8f15f31c upgrade superjson (#3162)
(patch)
2022-02-09 10:51:50 -05:00
Brandon Bayer
600467035a fix blitz logging to respect FORCE_COLOR=0 (#3157)
(patch)
2022-02-09 12:40:12 +01:00
Aleksandra Sikora
d25aee1313 Bump @prisma/sdk in installer and cli packages (#3158)
(ignore)
2022-02-08 13:45:33 +01:00
dependabot[bot]
0cc2a3aab7 Bump node-fetch from 2.6.1 to 2.6.7 in /nextjs (#3156)
(ignore)
2022-02-08 11:09:14 +01:00
Mochi
75e6b9fb74 Add NextUI recipe (#3152)
(recipe)
2022-02-07 11:50:50 +01:00
Aleksandra Sikora
6e8a65fa7f Update sponsors list (#3153)
(ignore)
2022-01-28 17:01:24 +01:00
Blitz.js Bot
01dce6b09a (meta) added @ReykCS as contributor 2022-01-26 14:21:20 -05:00
Aleksandra Sikora
ceeed729c6 Remove outdated tests (#3141)
(ignore)
2022-01-24 13:16:40 +01:00
Blitz.js Bot
7f35af5bd2 (meta) added @husnuljahneer as contributor 2022-01-23 08:30:20 -05:00
Blitz.js Bot
c603195004 (meta) added @shellord as contributor 2022-01-21 05:45:44 -05:00
saheenshoukath
bac35e06c8 Add @shellord as L1 maintainer (#3140) 2022-01-21 11:45:39 +01:00
Aleksandra
7add9cad87 bump recipe/example versions (ignore) 2022-01-20 11:41:47 +01:00
Aleksandra
16dae9b081 v0.45.2 2022-01-20 11:40:16 +01:00
Brandon Bayer
9f52f36c18 Fix passport adapter secureProxy to always work regardless of request headers (#3135)
(patch)
2022-01-19 17:29:21 -05:00
Aleksandra
621d87fdb7 bump recipe/example versions (ignore) 2022-01-18 18:28:24 +01:00
Aleksandra
871e709076 v0.45.1 2022-01-18 18:27:00 +01:00
Brandon Bayer
1e3ae5d445 fix passport adapter to work behind cloudfront (#3132)
(patch)
2022-01-18 12:11:23 -05:00
Aleksandra Sikora
a344c1f89e Update Seedling Sponsors list (#3130)
(ignore)
2022-01-17 11:02:34 +01:00
Blitz.js Bot
ee742530d9 (meta) added @Nfinished as contributor 2022-01-10 07:17:38 -05:00
Adam Trager
f102f4c873 Fix useRedirectAuthenticatedSession is not a function (#3117)
(patch)
2022-01-10 13:17:32 +01:00
Aleksandra
eebeeee6b7 bump recipe/example versions (ignore) 2022-01-06 16:27:01 +01:00
Aleksandra
18842fd56f v0.45.0 2022-01-06 16:25:41 +01:00
Blitz.js Bot
ea1e75b355 (meta) added @ospfranco as contributor 2022-01-04 06:59:45 -05:00
Aleksandra Sikora
34ed51a0db Fix blitz g mutation creating a file with invalid name (#3104)
(patch)
2022-01-03 19:24:08 +01:00
Marcus Reinhardt
4ce4bb92bb Add addRunCommandStep to the recipe builder (#3090)
(recipes)
2022-01-03 17:00:05 +01:00
Blitz.js Bot
75ed86eafb (meta) added @maltekiessling as contributor 2022-01-01 15:57:06 -05:00
Blitz.js Bot
a4bcfb4737 (meta) added @dineshgadge as contributor 2021-12-29 13:05:08 -05:00
Dinesh Gadge
bfd3be403e Fix RedirectError not redirecting on the client (#3100)
(patch)
2021-12-29 19:05:03 +01:00
Brandon Bayer
bfd75229c1 bump recipe/example versions (ignore) 2021-12-24 12:54:12 -05:00
Brandon Bayer
91172b82d9 v0.45.0-canary.0 2021-12-24 12:52:42 -05:00
Blitz.js Bot
c9f416713a (meta) added @robertrisch as contributor 2021-12-23 09:24:26 -05:00
Blitz.js Bot
11eb4208e6 (meta) added @arpitdalal as contributor 2021-12-21 17:18:42 -05:00
Aleksandra Sikora
fbd387a30c Update sponsors list (#3089)
(ignore)
2021-12-21 17:44:56 +01:00
Blitz.js Bot
018e2405f2 (meta) added @c-ciobanu as contributor 2021-12-21 07:59:16 -05:00
Blitz.js Bot
c631f1ef15 (meta) added @sarahdayan as contributor 2021-12-20 12:21:38 -05:00
Sarah Dayan
3ce4f97de7 Update links to PostgreSQL guide (#3087)
(meta)
2021-12-20 18:21:33 +01:00
JuanM04
77ad2c02ce Update material-ui recipe — remove @mui/styles (#3076)
(recipe)
2021-12-20 15:19:51 +01:00
Aleksandra Sikora
ecf5a29e19 Support custom templates folder with blitz generate (#3068)
(minor)
2021-12-17 16:42:58 +01:00
Blitz.js Bot
ec8632a3e9 (meta) added @kreako as contributor 2021-12-16 09:11:53 -05:00
Blitz.js Bot
98f91e24c1 (meta) added @SofianeDjellouli as contributor 2021-12-14 05:56:59 -05:00
Blitz.js Bot
49c5a1e1be (meta) updated @zenhob contributions 2021-12-14 05:50:28 -05:00
Francesco Sardo
9a00412049 Fix inconsistent formatting in LoginForm component and Login page (#3063)
(newapp)
2021-12-13 16:48:04 +01:00
John Vandivier
03fd49bb29 Use free tier by default in Render recipe (#3060)
(recipe)
2021-12-13 12:41:13 +01:00
Brandon Bayer
8b607b9463 bump recipe/example versions (ignore) 2021-12-11 17:00:54 -05:00
Brandon Bayer
e3472171a5 v0.44.4 2021-12-11 16:59:28 -05:00
Aleksandra Sikora
5f1c6a4571 Move installer package to nextjs/packages (#3044)
(patch)
2021-12-10 13:26:54 +01:00
Mochi
d05f00c0a8 Update tailwindcss recipe to v3 (#3050)
(recipe)
2021-12-10 12:22:13 +01:00
Aleksandra Sikora
0715bb7a02 Load env vars for blitz new command - ignore cached variables (#3043)
(patch)
2021-12-09 19:30:49 +01:00
JuanM04
00d1ddff0b Set blitz version to latest in new apps templates (#3048)
(newapp)
2021-12-09 15:52:56 +01:00
Blitz.js Bot
0f99de91ae (meta) added @skotchpine as contributor 2021-12-08 13:18:08 -05:00
tyler
9cff223033 Load nested mutations and queries in blitz console (#3031)
(patch)
2021-12-08 19:18:02 +01:00
Aleksandra Sikora
1d6021dd36 Upgrade @mrleebo/prisma-ast version and fix breaking @db.Text (#3041)
(patch)
2021-12-08 18:20:04 +01:00
Aleksandra Sikora
c4df5d8d04 Remove nullish coalescing from post-install script (#3040)
(patch)
2021-12-08 16:25:02 +01:00
Brandon Bayer
9019f1cf27 bump recipe/example versions (ignore) 2021-12-06 18:19:46 -05:00
Brandon Bayer
d92b7efe00 v0.44.3 2021-12-06 18:18:25 -05:00
Brandon Bayer
daea45eeb2 relax some unnecessary type requirements for blitz.config.ts (#3036)
(patch)
2021-12-06 18:17:02 -05:00
Brandon Bayer
8dcc5ebe23 fix blitz build not loading production env by default (#3037)
(patch)
2021-12-06 18:16:41 -05:00
Brandon Bayer
d36138361d bump recipe/example versions (ignore) 2021-12-06 15:56:24 -05:00
Brandon Bayer
831b0d4bcd v0.44.2 2021-12-06 15:55:01 -05:00
Brandon Bayer
5d9fcd22be fix env file loading to default to development instead of production (#3033)
(patch)
2021-12-06 15:52:50 -05:00
Brandon Bayer
1c51ab403b fix so that blitz config env config values can be type string | undefined (#3034)
(patch)
2021-12-06 15:52:09 -05:00
Brandon Bayer
c3c9e89302 bump recipe/example versions (ignore) 2021-12-06 13:05:55 -05:00
Brandon Bayer
e842c9f224 v0.44.1 2021-12-06 13:04:26 -05:00
JuanM04
abeb0c5d14 Fix APP_ENV loading to not load all .env files (#3026)
Co-authored-by: Brandon Bayer <b@bayer.ws> (patch)
2021-12-06 13:02:41 -05:00
Brandon Bayer
18d1a685a9 Fix windows incompatibility with nested dependency (#3030)
(patch)
2021-12-06 12:56:48 -05:00
Blitz.js Bot
9255050eee (meta) added @MukulKolpe as contributor 2021-12-06 12:20:37 -05:00
Mukul Kolpe
915f5fa479 Fix next_stdlib__WEBPACK_IMPORTED_MODULE_1__.connectMiddleware is not a function (#3024)
(patch)
2021-12-06 12:20:32 -05:00
Aleksandra Sikora
24dcac6978 Fix jest-preset syntax error (#3027)
(patch)
2021-12-06 11:50:04 -05:00
JuanM04
adef11ba8e Update default app blitz-env.d.ts 2021-12-05 19:45:18 -03:00
Blitz.js Bot
4233caa909 (meta) added @david-arteaga as contributor 2021-12-05 09:47:39 -05:00
Aleksandra
8f5cad91d4 bump recipe/example versions (ignore) 2021-12-03 22:55:11 +01:00
Aleksandra
ac5121beda v0.44.0 2021-12-03 22:53:40 +01:00
Aleksandra Sikora
5460fbb484 Move display package to nextjs fork (#2989)
(meta)
2021-12-03 16:46:55 -05:00
Aleksandra Sikora
ad71e15290 Make prefetching work with usePaginatedQuery and useInfiniteQuery (#3014)
(patch)
2021-12-03 20:54:40 +01:00
Aleksandra Sikora
4aba0d31f6 Load env variables based on APP_ENV or -e flag (#2878)
(minor)
2021-12-03 16:05:37 +01:00
Blitz.js Bot
19ad91709e (meta) added @divpreet as contributor 2021-12-03 08:23:32 -05:00
Blitz.js Bot
74efbad6d0 (meta) added @ajanth97 as contributor 2021-11-27 07:58:45 -05:00
Ilya
0fd6a4d5e3 Support RouteUrlObject as redirect.destination in GetServerSideProps/GetStaticProps (#2932)
(minor)
2021-11-24 14:12:47 +01:00
Blitz.js Bot
1c12da5495 (meta) added @davidchristie as contributor 2021-11-24 04:41:37 -05:00
Aleksandra Sikora
c4c90477c5 Upgrade react to 18-beta in new app templates (#2998)
(newapp)
2021-11-23 14:11:24 +01:00
dependabot[bot]
a9aaeec047 Bump tar from 2.2.2 to 4.4.18 in /nextjs (#2996)
(patch)
2021-11-22 13:33:28 +01:00
JuanM04
8420f6ddb8 Add "volta" settings to package.json and update node-version (#2994)
(meta)
2021-11-22 12:30:12 +01:00
Brandon Bayer
3a1ea75a55 fix missing BlitzConfig type (#2987)
(patch)
2021-11-19 18:11:28 +01:00
Blitz.js Bot
b23c2cdc36 (meta) added @noxify as contributor 2021-11-18 11:44:27 -05:00
Marcus Reinhardt
12c081b830 Add info about a required manual step to graphql-apollo-server recipe (#2905)
(recipe)
2021-11-18 17:44:21 +01:00
Aleksandra Sikora
11492dcfbd Upgrade typescript to 4.5 (#2973)
(newapp)
2021-11-18 15:50:43 +01:00
JuanM04
de874ca20e Fix lint warnings (#2968)
(meta)
2021-11-18 14:00:50 +01:00
Brandon Bayer
92ab9c3867 move blitz babel config into nextjs fork (#2903)
(patch)
2021-11-17 19:19:49 -05:00
Aleksandra
12c1b7331b bump recipe/example versions (ignore) 2021-11-17 17:29:35 +01:00
333 changed files with 6434 additions and 3319 deletions

View File

@@ -309,7 +309,8 @@
"profile": "https://github.com/Zeko369",
"contributions": [
"code",
"doc"
"doc",
"test"
]
},
{
@@ -625,7 +626,8 @@
"avatar_url": "https://avatars0.githubusercontent.com/u/17050715?v=4",
"profile": "https://cloudnweb.dev/",
"contributions": [
"code"
"code",
"test"
]
},
{
@@ -970,7 +972,9 @@
"avatar_url": "https://avatars0.githubusercontent.com/u/3496193?v=4",
"profile": "https://twitter.com/dillonraphael",
"contributions": [
"code"
"code",
"test",
"doc"
]
},
{
@@ -2964,7 +2968,8 @@
"avatar_url": "https://avatars.githubusercontent.com/u/12092?v=4",
"profile": "http://zackhobson.com/",
"contributions": [
"code"
"code",
"doc"
]
},
{
@@ -3065,7 +3070,8 @@
"avatar_url": "https://avatars.githubusercontent.com/u/8077469?v=4",
"profile": "https://andreas.fyi",
"contributions": [
"code"
"code",
"test"
]
},
{
@@ -3471,6 +3477,374 @@
"contributions": [
"doc"
]
},
{
"login": "noxify",
"name": "Marcus Reinhardt",
"avatar_url": "https://avatars.githubusercontent.com/u/521777?v=4",
"profile": "https://jammeryhq.com",
"contributions": [
"doc",
"code"
]
},
{
"login": "davidchristie",
"name": "David Christie",
"avatar_url": "https://avatars.githubusercontent.com/u/12044333?v=4",
"profile": "https://github.com/davidchristie",
"contributions": [
"doc"
]
},
{
"login": "ajanth97",
"name": "Ajanth",
"avatar_url": "https://avatars.githubusercontent.com/u/50458502?v=4",
"profile": "https://github.com/ajanth97",
"contributions": [
"doc"
]
},
{
"login": "divpreet",
"name": "Div",
"avatar_url": "https://avatars.githubusercontent.com/u/2805650?v=4",
"profile": "https://github.com/divpreet",
"contributions": [
"doc"
]
},
{
"login": "david-arteaga",
"name": "David Arteaga",
"avatar_url": "https://avatars.githubusercontent.com/u/7199015?v=4",
"profile": "https://github.com/david-arteaga",
"contributions": [
"doc"
]
},
{
"login": "MukulKolpe",
"name": "Mukul Kolpe",
"avatar_url": "https://avatars.githubusercontent.com/u/78664749?v=4",
"profile": "https://github.com/MukulKolpe",
"contributions": [
"code"
]
},
{
"login": "skotchpine",
"name": "tyler",
"avatar_url": "https://avatars.githubusercontent.com/u/13043909?v=4",
"profile": "https://github.com/skotchpine",
"contributions": [
"code"
]
},
{
"login": "SofianeDjellouli",
"name": "Sofiane Djellouli",
"avatar_url": "https://avatars.githubusercontent.com/u/38258952?v=4",
"profile": "https://github.com/SofianeDjellouli",
"contributions": [
"doc"
]
},
{
"login": "kreako",
"name": "kreako",
"avatar_url": "https://avatars.githubusercontent.com/u/65113001?v=4",
"profile": "https://github.com/kreako",
"contributions": [
"doc"
]
},
{
"login": "sarahdayan",
"name": "Sarah Dayan",
"avatar_url": "https://avatars.githubusercontent.com/u/5370675?v=4",
"profile": "https://sarahdayan.dev",
"contributions": [
"code"
]
},
{
"login": "c-ciobanu",
"name": "Cristi Ciobanu",
"avatar_url": "https://avatars.githubusercontent.com/u/33382714?v=4",
"profile": "https://github.com/c-ciobanu",
"contributions": [
"doc"
]
},
{
"login": "arpitdalal",
"name": "Arpit Dalal",
"avatar_url": "https://avatars.githubusercontent.com/u/61059807?v=4",
"profile": "https://arpitdalal.dev",
"contributions": [
"doc"
]
},
{
"login": "robertrisch",
"name": "robertrisch",
"avatar_url": "https://avatars.githubusercontent.com/u/73828816?v=4",
"profile": "https://github.com/robertrisch",
"contributions": [
"doc"
]
},
{
"login": "dineshgadge",
"name": "Dinesh Gadge",
"avatar_url": "https://avatars.githubusercontent.com/u/186976?v=4",
"profile": "https://github.com/dineshgadge",
"contributions": [
"code"
]
},
{
"login": "maltekiessling",
"name": "Malte Kießling",
"avatar_url": "https://avatars.githubusercontent.com/u/30420110?v=4",
"profile": "https://github.com/maltekiessling",
"contributions": [
"doc"
]
},
{
"login": "ospfranco",
"name": "Oscar Franco",
"avatar_url": "https://avatars.githubusercontent.com/u/1634213?v=4",
"profile": "ospfranco.com",
"contributions": [
"doc"
]
},
{
"login": "Nfinished",
"name": "Adam Trager",
"avatar_url": "https://avatars.githubusercontent.com/u/1719791?v=4",
"profile": "adamtrager.com",
"contributions": [
"code"
]
},
{
"login": "shellord",
"name": "saheenshoukath",
"avatar_url": "https://avatars.githubusercontent.com/u/2632896?v=4",
"profile": "https://saheen.codes",
"contributions": [
"doc"
]
},
{
"login": "husnuljahneer",
"name": "Husnul Jahneer",
"avatar_url": "https://avatars.githubusercontent.com/u/54552763?v=4",
"profile": "https://jahneer.me",
"contributions": [
"doc"
]
},
{
"login": "ReykCS",
"name": "Reyk",
"avatar_url": "https://avatars.githubusercontent.com/u/40463716?v=4",
"profile": "https://github.com/ReykCS",
"contributions": [
"doc"
]
},
{
"login": "Lokprakash-babu",
"name": "Lokprakash Babu",
"avatar_url": "https://avatars.githubusercontent.com/u/60031382?v=4",
"profile": "https://github.com/Lokprakash-babu",
"contributions": [
"doc"
]
},
{
"login": "eai04191",
"name": "eai04191",
"avatar_url": "https://avatars.githubusercontent.com/u/3516343?v=4",
"profile": "https://mizle.net",
"contributions": [
"doc"
]
},
{
"login": "numanaral",
"name": "Numan",
"avatar_url": "https://avatars.githubusercontent.com/u/25233323?v=4",
"profile": "https://numanaral.github.io/?ref=github",
"contributions": [
"doc"
]
},
{
"login": "jscyo",
"name": "Joel Coutinho",
"avatar_url": "https://avatars.githubusercontent.com/u/6310783?v=4",
"profile": "https://github.com/jscyo",
"contributions": [
"doc"
]
},
{
"login": "davidbarker",
"name": "David Barker",
"avatar_url": "https://avatars.githubusercontent.com/u/1597139?v=4",
"profile": "https://github.com/davidbarker",
"contributions": [
"doc"
]
},
{
"login": "timfee",
"name": "Tim Feeley",
"avatar_url": "https://avatars.githubusercontent.com/u/3246342?v=4",
"profile": "http://www.timfeeley.com/",
"contributions": [
"code"
]
},
{
"login": "Caslus",
"name": "lucas philippe",
"avatar_url": "https://avatars.githubusercontent.com/u/22855640?v=4",
"profile": "https://github.com/Caslus",
"contributions": [
"doc"
]
},
{
"login": "the-bayer",
"name": "Blake Bayer",
"avatar_url": "https://avatars.githubusercontent.com/u/94391693?v=4",
"profile": "https://github.com/the-bayer",
"contributions": [
"code",
"doc"
]
},
{
"login": "rmassie",
"name": "R Massie",
"avatar_url": "https://avatars.githubusercontent.com/u/7375518?v=4",
"profile": "https://github.com/rmassie",
"contributions": [
"doc"
]
},
{
"login": "paulm17",
"name": "Paul",
"avatar_url": "https://avatars.githubusercontent.com/u/387463?v=4",
"profile": "https://github.com/paulm17",
"contributions": [
"doc"
]
},
{
"login": "minho42",
"name": "Min ho Kim",
"avatar_url": "https://avatars.githubusercontent.com/u/15278512?v=4",
"profile": "https://minho42.com",
"contributions": [
"doc"
]
},
{
"login": "webdeb",
"name": "webdeb",
"avatar_url": "https://avatars.githubusercontent.com/u/14992140?v=4",
"profile": "https://github.com/webdeb",
"contributions": [
"doc"
]
},
{
"login": "iDavidB",
"name": "David",
"avatar_url": "https://avatars.githubusercontent.com/u/32268383?v=4",
"profile": "https://github.com/iDavidB",
"contributions": [
"doc",
"code",
"test"
]
},
{
"login": "jakedee",
"name": "Jake Dowie",
"avatar_url": "https://avatars.githubusercontent.com/u/5058625?v=4",
"profile": "https://jdlt.co.uk",
"contributions": [
"doc"
]
},
{
"login": "datner",
"name": "Datner",
"avatar_url": "https://avatars.githubusercontent.com/u/22598347?v=4",
"profile": "https://github.com/datner",
"contributions": [
"doc",
"code",
"test"
]
},
{
"login": "remlse",
"name": "remlse",
"avatar_url": "https://avatars.githubusercontent.com/u/54984957?v=4",
"profile": "https://github.com/remlse",
"contributions": [
"doc"
]
},
{
"login": "sergous",
"name": "Sergei Smirnov",
"avatar_url": "https://avatars.githubusercontent.com/u/545151?v=4",
"profile": "https://github.com/sergous",
"contributions": [
"doc"
]
},
{
"login": "Trancever",
"name": "Dawid Urbaniak",
"avatar_url": "https://avatars.githubusercontent.com/u/18584155?v=4",
"profile": "https://twitter.com/trensik",
"contributions": [
"doc",
"code"
]
},
{
"login": "SerekKiri",
"name": "Kacper Potyrała",
"avatar_url": "https://avatars.githubusercontent.com/u/29735836?v=4",
"profile": "kiri.dev",
"contributions": [
"doc"
]
},
{
"login": "iojcde",
"name": "Jeeho Ahn",
"avatar_url": "https://avatars.githubusercontent.com/u/31413538?v=4",
"profile": "jcde.xyz",
"contributions": [
"doc",
"tool"
]
}
],
"contributorsPerLine": 7,

4
.github/CODEOWNERS vendored
View File

@@ -1,8 +1,8 @@
# https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners
* @flybayer @beerose
* @beerose
# packages/cli/**/* @aem, @flybayer
# packages/generator/**/* @aem @flybayer
packages/generator/templates**/* @flybayer
# packages/generator/templates**/* @flybayer
# packages/installer/**/* @aem @flybayer

View File

@@ -15,6 +15,10 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: "14"
- name: Count size
uses: preactjs/compressed-size-action@v2
with:

View File

@@ -30,9 +30,9 @@ jobs:
path: |
${{ steps.yarn-cache-dir-path.outputs.dir }}
**/node_modules
key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v13-${{ hashFiles('yarn.lock') }}
key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v14-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ runner.node_version}}-yarn-v13-
${{ runner.os }}-${{ runner.node_version}}-yarn-v14-
- name: Install dependencies
run: yarn install --frozen-lockfile --silent
env:
@@ -74,9 +74,9 @@ jobs:
path: |
${{ steps.yarn-cache-dir-path.outputs.dir }}
**/node_modules
key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v13-${{ hashFiles('yarn.lock') }}
key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v14-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ runner.node_version}}-yarn-v13-
${{ runner.os }}-${{ runner.node_version}}-yarn-v14-
- run: yarn install --frozen-lockfile --check-files
- name: Build Packages
run: yarn build
@@ -98,6 +98,10 @@ jobs:
with:
path: ./*
key: ${{ runner.os }}-${{ github.sha }}
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: "14"
- name: Setup kernel to increase watchers
if: runner.os == 'Linux'
run: echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
@@ -106,6 +110,33 @@ jobs:
env:
CI: true
testNextPackages:
name: Next - Test Packages
defaults:
run:
working-directory: nextjs
needs: build-linux
runs-on: ubuntu-latest
env:
BLITZ_TELEMETRY_DISABLED: 1
steps:
- uses: actions/cache@v2
id: restore-build
with:
path: ./*
key: ${{ runner.os }}-${{ github.sha }}
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: "14"
- name: Setup kernel to increase watchers
if: runner.os == 'Linux'
run: echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
- name: Test Next Packages
run: yarn testonly:packages
env:
CI: true
testBlitzExamples:
timeout-minutes: 30
name: Blitz - Test Example Apps (ubuntu-latest)
@@ -120,6 +151,10 @@ jobs:
with:
path: ./*
key: ${{ runner.os }}-${{ github.sha }}
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: "14"
# Needed to get cypress binary
- run: yarn cypress install
- name: Install sass
@@ -157,9 +192,9 @@ jobs:
# path: |
# ${{ steps.yarn-cache-dir-path.outputs.dir }}
# **/node_modules
# key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v13-${{ hashFiles('yarn.lock') }}
# key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v14-${{ hashFiles('yarn.lock') }}
# restore-keys: |
# ${{ runner.os }}-${{ runner.node_version}}-yarn-v13-
# ${{ runner.os }}-${{ runner.node_version}}-yarn-v14-
- run: yarn install --frozen-lockfile --check-files
- name: Build Packages
run: yarn build
@@ -222,6 +257,10 @@ jobs:
with:
path: ./*
key: ${{ runner.os }}-${{ github.sha }}
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: "14"
# TODO: remove after we fix watchpack watching too much
- name: Setup kernel to increase watchers
@@ -256,9 +295,9 @@ jobs:
# path: |
# ${{ steps.yarn-cache-dir-path.outputs.dir }}
# **/node_modules
# key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v13-${{ hashFiles('yarn.lock') }}
# key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v14-${{ hashFiles('yarn.lock') }}
# restore-keys: |
# ${{ runner.os }}-${{ runner.node_version}}-yarn-v13-
# ${{ runner.os }}-${{ runner.node_version}}-yarn-v14-
- run: yarn install --frozen-lockfile --check-files
- name: Build Packages
run: yarn build
@@ -285,7 +324,10 @@ jobs:
with:
path: ./*
key: ${{ runner.os }}-${{ github.sha }}
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: "14"
# TODO: remove after we fix watchpack watching too much
- name: Setup kernel to increase watchers
if: runner.os == 'Linux'
@@ -318,9 +360,9 @@ jobs:
# path: |
# ${{ steps.yarn-cache-dir-path.outputs.dir }}
# **/node_modules
# key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v13-${{ hashFiles('yarn.lock') }}
# key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v14-${{ hashFiles('yarn.lock') }}
# restore-keys: |
# ${{ runner.os }}-${{ runner.node_version}}-yarn-v13-
# ${{ runner.os }}-${{ runner.node_version}}-yarn-v14-
- run: yarn install --frozen-lockfile --check-files
- name: Build Packages
run: yarn build
@@ -363,6 +405,7 @@ jobs:
testIntegrationBlitzWin,
testUnit,
testBlitzPackages,
testNextPackages,
testBlitzExamples,
testBlitzExamplesWin,
]

View File

@@ -1 +1 @@
16.13.0
14.18.1

View File

@@ -4,6 +4,12 @@
## Notes For Core Team
### To Publish a new NPM Package under `@blitzjs/` namespace
1. cd into the package directory
2. Run `npm publish --tag danger --access public`
- `--access public` is required because scoped packages are set to private by default
### Syncing Next.js Fork
1. Run `yarn push-nextjs`

112
README.md
View File

@@ -6,7 +6,7 @@
<img alt="" src="https://img.shields.io/badge/Join%20our%20community-6700EB.svg?style=for-the-badge&labelColor=000000&logoWidth=20&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAQ9SURBVHgB7d3dVdtAEIbhcSpICUoH0IEogQqSVBBSAU4FSSpIOoAORAfQgSghHXzZ1U/YcMD4R9rZmf2ec3y448LyiNf27iLiGIAmPLrweC9Un3DhrzG6EarLNP09nlwJ1SOZ/lQr5N80/S/p2QMVCBf5N17XCfm1Y/rBHqjAG9PPHvBsz+mf9WAP+HLA9M/YA14cOP2payH7jpj+VCtk1wnTP+vj7xCy6cTpn7EHLMLp059iD1iD8eveJbVCNsSLheX1YA/YgOWnf8YeKB3Wmf7Ud6Fy4f/FHmtpxbl3YlC4MJ/Cj0bWdwPnPbARg+L0S54XQHS32WwuxClzd4CM0z9rPfeAuTtA5ulPXYQ7wZ04Y+oOoDD9KZc9YOoOoDj9s4dwFzgXR6w1wIPoOvPWA9buAHEJ173o3gWiy3AnuBUHLEbgmYwvAk1/wuM8vAgexThzbwPDkx7/DHwVXfFOxP2GmsKd4Ab6zPeAyU8CI7AHFmH2BRCBPXAyk18GzUrqAXCTiR4ssyj0VFw/oCU8+e+RZ33AWz6KMaYbIIWxB+JSLs1bsbkeMN0AqakHvoku9oA2sAfqBvbAQdw0QArsgb25aYBUQT3QgT2gB+yBuqGcHij2UCqXDZACe2Anlw2QYg/QAOyBuoE98CL3DZDCuK4/rh/Q7oGL6U+TOvcNkJoijN8X1C48+T+g75eQDrAH/qmqAVJgDwyqaoAUe4AGYA/UDZX3QLUNkEIZPRCd5+6BahsgVUgPROwBTSijB7jpVAvGHriHvmw9wAZ4BpX1ABvgmakHtPcbRuwBTWAPULgAV9D/jKDY9YRvwvgEaurD44uQHvAol7qBW7WKluVtIHiUS7GyvA0s6CiXDnxrpQfsgbqBS7GKk/2jYHCrVlGyfxTMrVo0ALdq1Q3sgSKofh0M9oA61a+D2QM0AHugbmAPqClmSRjK2apVVQ8UsySsoK1aHdgDesCtWnUDeyCrIpeFg1u3sylyWTi3btMA7IG6gT2wuuK3hoE9sKrit4YVslWLPaAN7IG6ocKt2zmY2h4O9sDiTG0PZw/QANy6XTewBxZj9ogYVHy025LMHhEz9cBn0We6B0yfERReBLfhx0/R1YQHPx/QBPbA0VwcEwf2wNFcHBPHHjiem3MC2QPHcXdSaJjA+KfgTPQ8hhfjBzHC40mhlzJ+Xq9lK4a4PCs43AVaGTed5mZq+iOXZwWHi3AnOj2wFWNcnxYe7gTxLtBKHuamP/J+Wnh8a5irB7ZC5Yk9gPX1QuXC+usHWqGyhYvUYR0a7zboUOFCNVhnk0krZAOW7wFOvzXhom2xnEbIHizTA1wEYhWW6YFGyC6c1gOcfg9wfA80Qj7g8B7g9HuCww+haIR8wf49wOn3Cvv9k8tGyC/s7gFOv3fY3QONkH+v9MBWqB7PeqDn9FcIT//kcitUn6kHOu/T/xfWzlQy3dEHhwAAAABJRU5ErkJggg==">
</a>
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
<a aria-label="All Contributors" href="#contributors-"><img alt="" src="https://img.shields.io/badge/all_contributors-368-17BB8A.svg?style=for-the-badge&labelColor=000000"></a>
<a aria-label="All Contributors" href="#contributors-"><img alt="" src="https://img.shields.io/badge/all_contributors-408-17BB8A.svg?style=for-the-badge&labelColor=000000"></a>
<!-- ALL-CONTRIBUTORS-BADGE:END -->
<a aria-label="License" href="https://github.com/blitz-js/blitz/blob/canary/LICENSE">
<img alt="" src="https://img.shields.io/npm/l/blitz.svg?style=for-the-badge&labelColor=000000&color=blue">
@@ -107,18 +107,21 @@ Your financial contributions help ensure Blitz continues to be developed and mai
<table>
<tr>
<td><a aria-label="Andreas Asprou" href="https://andreas.fyi">
<img alt="" src="https://raw.githubusercontent.com/blitz-js/blitz/canary/assets/andreas.jpg" width="40px"/>
</a></td>
<td><a aria-label="Digas" href="https://digsas.com">
<img alt="" src="https://raw.githubusercontent.com/blitz-js/blitz/canary/assets/digsas.svg" width="40px"/>
</a></td>
<td><a aria-label="userTrack" href="https://www.usertrack.net/?ref=blitzjs">
<img alt="" src="https://raw.githubusercontent.com/blitz-js/blitz/canary/assets/usertrack.png" width="40px"/>
</a></td>
<td><a aria-label="MeetKai" href="https://meetkai.com/?ref=blitzjs">
<img alt="" src="https://raw.githubusercontent.com/blitz-js/blitz/canary/assets/meetkai.png" width="40px"/>
</a></td>
<td>
<a aria-label="Andreas Asprou" href="https://andreas.fyi">
<img alt="" src="https://raw.githubusercontent.com/blitz-js/blitz/canary/assets/andreas.jpg" width="40px"/>
</a>
</td>
<td>
<a aria-label="MeetKai" href="https://meetkai.com/?ref=blitzjs">
<img alt="" src="https://raw.githubusercontent.com/blitz-js/blitz/canary/assets/meetkai.png" width="40px"/>
</a>
</td>
<td>
<a aria-label="JDLT" href="https://jdlt.co.uk/?ref=blitzjs">
<img alt="" src="https://raw.githubusercontent.com/blitz-js/blitz/canary/assets/jdlt.png" width="40px"/>
</a>
</td>
</tr>
</table>
@@ -149,11 +152,6 @@ Your financial contributions help ensure Blitz continues to be developed and mai
<a aria-label="Fauna" href="https://dashboard.fauna.com/accounts/register?utm_source=BlitzJS&utm_medium=sponsorship&utm_campaign=BlitzJS_Sponsorship_2020">
<img alt="" src="https://raw.githubusercontent.com/blitz-js/blitz/canary/assets/Fauna_Logo_Blue.png" width="300px">
</a>
</td>
<td>
<a aria-label="GraphCMS" href="https://graphcms.com/?utm_source=BlitzJS&utm_medium=sponsorship&utm_campaign=BlitzJS_Sponsorship_2021">
<img alt="" src="https://raw.githubusercontent.com/blitz-js/blitz/canary/assets/graphcms.png" width="300px">
</a>
</td>
</tr>
</table>
@@ -239,6 +237,22 @@ _Issue triage, pull request triage, community encouragement and moderation, etc_
</sub>
</a>
</td>
<td align="center">
<a href="https://www.saheen.me/">
<img src="https://avatars.githubusercontent.com/shellord" width="100px;" alt="Saheen Shoukath avatar" /><br />
<sub>
<b>Saheen Shoukath</b>
</sub>
</a>
</td>
<td align="center">
<a href="https://jahneer.me">
<img src="https://avatars.githubusercontent.com/husnuljahneer" width="100px;" alt="Husnul Jahneer avatar" /><br />
<sub>
<b>Husnul Jahneer</b>
</sub>
</a>
</td>
</tr>
</table>
<!-- markdownlint-enable -->
@@ -293,7 +307,7 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
</tr>
<tr>
<td align="center"><a href="https://github.com/sonnypgs"><img src="https://avatars3.githubusercontent.com/u/1431300?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sonny</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=sonnypgs" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/Zeko369"><img src="https://avatars3.githubusercontent.com/u/3064377?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Fran Zekan</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Zeko369" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=Zeko369" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/Zeko369"><img src="https://avatars3.githubusercontent.com/u/3064377?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Fran Zekan</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Zeko369" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=Zeko369" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=Zeko369" title="Tests">⚠️</a></td>
<td align="center"><a href="http://twitter.com/JanBaykara"><img src="https://avatars2.githubusercontent.com/u/237556?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jan Baykara</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=janbaykara" title="Documentation">📖</a></td>
<td align="center"><a href="https://mikeattara.com"><img src="https://avatars1.githubusercontent.com/u/31483629?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mike Perry Y Attara</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=mikeattara" title="Documentation">📖</a></td>
<td align="center"><a href="https://devanthe.dev"><img src="https://avatars0.githubusercontent.com/u/354652?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Devan</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=DevanB" title="Documentation">📖</a></td>
@@ -334,7 +348,7 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
<td align="center"><a href="http://anteprimorac.com.hr"><img src="https://avatars0.githubusercontent.com/u/972083?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ante Primorac</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=anteprimorac" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=anteprimorac" title="Documentation">📖</a></td>
<td align="center"><a href="http://mykalmachon.dev"><img src="https://avatars1.githubusercontent.com/u/7844994?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mykal Machon</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=MykalMachon" title="Code">💻</a></td>
<td align="center"><a href="https://jamiedavenport.dev"><img src="https://avatars2.githubusercontent.com/u/1329874?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jamie Davenport</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=jamiedavenport" title="Code">💻</a> <a href="#maintenance-jamiedavenport" title="Maintenance">🚧</a></td>
<td align="center"><a href="https://cloudnweb.dev/"><img src="https://avatars0.githubusercontent.com/u/17050715?v=4?s=100" width="100px;" alt=""/><br /><sub><b>GaneshMani</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ganeshmani" title="Code">💻</a></td>
<td align="center"><a href="https://cloudnweb.dev/"><img src="https://avatars0.githubusercontent.com/u/17050715?v=4?s=100" width="100px;" alt=""/><br /><sub><b>GaneshMani</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ganeshmani" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=ganeshmani" title="Tests">⚠️</a></td>
</tr>
<tr>
<td align="center"><a href="http://ramonmorcillo.com"><img src="https://avatars3.githubusercontent.com/u/31936665?v=4?s=100" width="100px;" alt=""/><br /><sub><b>reymon359</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=reymon359" title="Code">💻</a></td>
@@ -383,7 +397,7 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
</tr>
<tr>
<td align="center"><a href="https://github.com/jschepmans"><img src="https://avatars2.githubusercontent.com/u/5782977?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Johan Schepmans</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=jschepmans" title="Code">💻</a></td>
<td align="center"><a href="https://twitter.com/dillonraphael"><img src="https://avatars0.githubusercontent.com/u/3496193?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dillon Raphael</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=dillonraphael" title="Code">💻</a></td>
<td align="center"><a href="https://twitter.com/dillonraphael"><img src="https://avatars0.githubusercontent.com/u/3496193?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dillon Raphael</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=dillonraphael" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=dillonraphael" title="Tests">⚠️</a> <a href="https://github.com/blitz-js/blitz/commits?author=dillonraphael" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/clgeoio"><img src="https://avatars2.githubusercontent.com/u/37571416?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Cody G</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=clgeoio" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=clgeoio" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/madflow"><img src="https://avatars0.githubusercontent.com/u/183248?v=4?s=100" width="100px;" alt=""/><br /><sub><b>madflow</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=madflow" title="Documentation">📖</a></td>
<td align="center"><a href="https://twitter.com/nitaking_"><img src="https://avatars2.githubusercontent.com/u/10850034?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Satoshi Nitawaki</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=nitaking" title="Code">💻</a> <a href="#maintenance-nitaking" title="Maintenance">🚧</a> <a href="#question-nitaking" title="Answering Questions">💬</a> <a href="https://github.com/blitz-js/blitz/commits?author=nitaking" title="Documentation">📖</a></td>
@@ -657,7 +671,7 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
<td align="center"><a href="https://github.com/bravo-kernel"><img src="https://avatars.githubusercontent.com/u/230500?v=4?s=100" width="100px;" alt=""/><br /><sub><b>bravo-kernel</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=bravo-kernel" title="Code">💻</a></td>
<td align="center"><a href="https://samholmes.net"><img src="https://avatars.githubusercontent.com/u/8385528?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sam Holmes</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=sam3d" title="Code">💻</a></td>
<td align="center"><a href="https://doncicuto.medium.com"><img src="https://avatars.githubusercontent.com/u/30386061?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Miguel Cabrerizo</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=doncicuto" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=doncicuto" title="Documentation">📖</a></td>
<td align="center"><a href="http://zackhobson.com/"><img src="https://avatars.githubusercontent.com/u/12092?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zack Hobson</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=zenhob" title="Code">💻</a></td>
<td align="center"><a href="http://zackhobson.com/"><img src="https://avatars.githubusercontent.com/u/12092?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zack Hobson</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=zenhob" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=zenhob" title="Documentation">📖</a></td>
<td align="center"><a href="https://www.mokhtar.dev"><img src="https://avatars.githubusercontent.com/u/13026820?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mokhtar</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=m5r" title="Documentation">📖</a></td>
</tr>
<tr>
@@ -672,7 +686,7 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
<tr>
<td align="center"><a href="https://github.com/ratson"><img src="https://avatars.githubusercontent.com/u/2682937?v=4?s=100" width="100px;" alt=""/><br /><sub><b>(◕ᴥ◕)</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ratson" title="Code">💻</a></td>
<td align="center"><a href="maciejmyslinski.com"><img src="https://avatars.githubusercontent.com/u/11421186?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mat Milbury</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=maciejmyslinski" title="Documentation">📖</a></td>
<td align="center"><a href="https://andreas.fyi"><img src="https://avatars.githubusercontent.com/u/8077469?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Andreas Asprou</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=andreasasprou" title="Code">💻</a></td>
<td align="center"><a href="https://andreas.fyi"><img src="https://avatars.githubusercontent.com/u/8077469?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Andreas Asprou</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=andreasasprou" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=andreasasprou" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/kotx"><img src="https://avatars.githubusercontent.com/u/33439542?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kot</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=kotx" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=kotx" title="Tests">⚠️</a> <a href="https://github.com/blitz-js/blitz/commits?author=kotx" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/isaka1022"><img src="https://avatars.githubusercontent.com/u/28589716?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Amane</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=isaka1022" title="Documentation">📖</a></td>
<td align="center"><a href="johnleung.com"><img src="https://avatars.githubusercontent.com/u/20699?v=4?s=100" width="100px;" alt=""/><br /><sub><b>John Leung</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=fuzzthink" title="Documentation">📖</a></td>
@@ -728,6 +742,58 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
<td align="center"><a href="https://danestves.com/"><img src="https://avatars.githubusercontent.com/u/31737273?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Daniel Esteves</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=danestves" title="Documentation">📖</a></td>
<td align="center"><a href="http://www.bitnative.com"><img src="https://avatars.githubusercontent.com/u/1688997?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Cory House</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=coryhouse" title="Documentation">📖</a></td>
<td align="center"><a href="https://auspham.dev/"><img src="https://avatars.githubusercontent.com/u/16440123?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Austin (Thang Pham)</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=rockmanvnx6" title="Documentation">📖</a></td>
<td align="center"><a href="https://jammeryhq.com"><img src="https://avatars.githubusercontent.com/u/521777?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Marcus Reinhardt</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=noxify" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=noxify" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/davidchristie"><img src="https://avatars.githubusercontent.com/u/12044333?v=4?s=100" width="100px;" alt=""/><br /><sub><b>David Christie</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=davidchristie" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/ajanth97"><img src="https://avatars.githubusercontent.com/u/50458502?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ajanth</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ajanth97" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/divpreet"><img src="https://avatars.githubusercontent.com/u/2805650?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Div</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=divpreet" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/david-arteaga"><img src="https://avatars.githubusercontent.com/u/7199015?v=4?s=100" width="100px;" alt=""/><br /><sub><b>David Arteaga</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=david-arteaga" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/MukulKolpe"><img src="https://avatars.githubusercontent.com/u/78664749?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mukul Kolpe</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=MukulKolpe" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/skotchpine"><img src="https://avatars.githubusercontent.com/u/13043909?v=4?s=100" width="100px;" alt=""/><br /><sub><b>tyler</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=skotchpine" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/SofianeDjellouli"><img src="https://avatars.githubusercontent.com/u/38258952?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sofiane Djellouli</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=SofianeDjellouli" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/kreako"><img src="https://avatars.githubusercontent.com/u/65113001?v=4?s=100" width="100px;" alt=""/><br /><sub><b>kreako</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=kreako" title="Documentation">📖</a></td>
<td align="center"><a href="https://sarahdayan.dev"><img src="https://avatars.githubusercontent.com/u/5370675?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sarah Dayan</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=sarahdayan" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/c-ciobanu"><img src="https://avatars.githubusercontent.com/u/33382714?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Cristi Ciobanu</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=c-ciobanu" title="Documentation">📖</a></td>
<td align="center"><a href="https://arpitdalal.dev"><img src="https://avatars.githubusercontent.com/u/61059807?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Arpit Dalal</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=arpitdalal" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/robertrisch"><img src="https://avatars.githubusercontent.com/u/73828816?v=4?s=100" width="100px;" alt=""/><br /><sub><b>robertrisch</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=robertrisch" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/dineshgadge"><img src="https://avatars.githubusercontent.com/u/186976?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dinesh Gadge</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=dineshgadge" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/maltekiessling"><img src="https://avatars.githubusercontent.com/u/30420110?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Malte Kießling</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=maltekiessling" title="Documentation">📖</a></td>
<td align="center"><a href="ospfranco.com"><img src="https://avatars.githubusercontent.com/u/1634213?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Oscar Franco</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ospfranco" title="Documentation">📖</a></td>
<td align="center"><a href="adamtrager.com"><img src="https://avatars.githubusercontent.com/u/1719791?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Adam Trager</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Nfinished" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://saheen.codes"><img src="https://avatars.githubusercontent.com/u/2632896?v=4?s=100" width="100px;" alt=""/><br /><sub><b>saheenshoukath</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=shellord" title="Documentation">📖</a></td>
<td align="center"><a href="https://jahneer.me"><img src="https://avatars.githubusercontent.com/u/54552763?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Husnul Jahneer</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=husnuljahneer" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/ReykCS"><img src="https://avatars.githubusercontent.com/u/40463716?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Reyk</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ReykCS" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/Lokprakash-babu"><img src="https://avatars.githubusercontent.com/u/60031382?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Lokprakash Babu</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Lokprakash-babu" title="Documentation">📖</a></td>
<td align="center"><a href="https://mizle.net"><img src="https://avatars.githubusercontent.com/u/3516343?v=4?s=100" width="100px;" alt=""/><br /><sub><b>eai04191</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=eai04191" title="Documentation">📖</a></td>
<td align="center"><a href="https://numanaral.github.io/?ref=github"><img src="https://avatars.githubusercontent.com/u/25233323?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Numan</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=numanaral" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/jscyo"><img src="https://avatars.githubusercontent.com/u/6310783?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Joel Coutinho</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=jscyo" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/davidbarker"><img src="https://avatars.githubusercontent.com/u/1597139?v=4?s=100" width="100px;" alt=""/><br /><sub><b>David Barker</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=davidbarker" title="Documentation">📖</a></td>
<td align="center"><a href="http://www.timfeeley.com/"><img src="https://avatars.githubusercontent.com/u/3246342?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tim Feeley</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=timfee" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Caslus"><img src="https://avatars.githubusercontent.com/u/22855640?v=4?s=100" width="100px;" alt=""/><br /><sub><b>lucas philippe</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Caslus" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/the-bayer"><img src="https://avatars.githubusercontent.com/u/94391693?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Blake Bayer</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=the-bayer" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=the-bayer" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/rmassie"><img src="https://avatars.githubusercontent.com/u/7375518?v=4?s=100" width="100px;" alt=""/><br /><sub><b>R Massie</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=rmassie" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/paulm17"><img src="https://avatars.githubusercontent.com/u/387463?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Paul</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=paulm17" title="Documentation">📖</a></td>
<td align="center"><a href="https://minho42.com"><img src="https://avatars.githubusercontent.com/u/15278512?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Min ho Kim</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=minho42" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/webdeb"><img src="https://avatars.githubusercontent.com/u/14992140?v=4?s=100" width="100px;" alt=""/><br /><sub><b>webdeb</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=webdeb" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/iDavidB"><img src="https://avatars.githubusercontent.com/u/32268383?v=4?s=100" width="100px;" alt=""/><br /><sub><b>David</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=iDavidB" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=iDavidB" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=iDavidB" title="Tests">⚠️</a></td>
<td align="center"><a href="https://jdlt.co.uk"><img src="https://avatars.githubusercontent.com/u/5058625?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jake Dowie</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=jakedee" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/datner"><img src="https://avatars.githubusercontent.com/u/22598347?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Datner</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=datner" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=datner" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=datner" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/remlse"><img src="https://avatars.githubusercontent.com/u/54984957?v=4?s=100" width="100px;" alt=""/><br /><sub><b>remlse</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=remlse" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/sergous"><img src="https://avatars.githubusercontent.com/u/545151?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sergei Smirnov</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=sergous" title="Documentation">📖</a></td>
<td align="center"><a href="https://twitter.com/trensik"><img src="https://avatars.githubusercontent.com/u/18584155?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dawid Urbaniak</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Trancever" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=Trancever" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="kiri.dev"><img src="https://avatars.githubusercontent.com/u/29735836?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kacper Potyrała</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=SerekKiri" title="Documentation">📖</a></td>
<td align="center"><a href="jcde.xyz"><img src="https://avatars.githubusercontent.com/u/31413538?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jeeho Ahn</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=iojcde" title="Documentation">📖</a> <a href="#tool-iojcde" title="Tools">🔧</a></td>
</tr>
</table>

View File

@@ -6,5 +6,5 @@ TODO
## Reporting a Vulnerability
Email Brandon Bayer at b@bayer.ws to report a vulnerablity, and he will follow up with you asap.
Email Brandon Bayer at b@bayer.ws to report a vulnerability, and he will follow up with you asap.

View File

@@ -1,24 +0,0 @@
<svg width="128" height="128" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0)">
<path d="M79.4831 1.95572C70.2813 -0.81923 55.2811 -0.617415 46.1549 2.4098L18.6125 11.5167C9.48627 14.5313 9.38542 19.7784 18.3856 23.1588L49.9743 35.028C58.9744 38.4084 73.6217 38.194 82.5084 34.5487L110.883 22.9192C119.782 19.2739 119.53 14.0267 110.316 11.2518L79.4831 1.95572Z" fill="url(#paint0_linear)"/>
<path d="M84.235 38.6101C75.3357 42.2554 68.0625 53.1029 68.0625 62.727V113.635C68.0625 123.259 74.9071 127.245 83.2644 122.489L109.282 107.706C117.639 102.951 124.912 91.208 125.442 81.6092L127.837 37.8281C128.366 28.2167 121.509 23.3479 112.609 26.9932L84.235 38.6101Z" fill="url(#paint1_linear)"/>
<path d="M0.0071345 37.8409C-0.257575 28.2295 6.877 23.1211 15.8771 26.5015L47.4658 38.3707C56.466 41.7511 63.8274 52.3842 63.8274 62.0082V112.916C63.8274 122.54 56.882 126.715 48.386 122.212L17.0998 105.6C8.60392 101.085 1.44415 89.5306 1.16683 79.9192L0.0071345 37.8409Z" fill="url(#paint2_linear)"/>
</g>
<defs>
<linearGradient id="paint0_linear" x1="63.9326" y1="0" x2="63.9326" y2="124.497" gradientUnits="userSpaceOnUse">
<stop stop-color="#036EB8"/>
<stop offset="1" stop-color="#469196"/>
</linearGradient>
<linearGradient id="paint1_linear" x1="63.9326" y1="0" x2="63.9326" y2="124.497" gradientUnits="userSpaceOnUse">
<stop stop-color="#036EB8"/>
<stop offset="1" stop-color="#469196"/>
</linearGradient>
<linearGradient id="paint2_linear" x1="63.9326" y1="0" x2="63.9326" y2="124.497" gradientUnits="userSpaceOnUse">
<stop stop-color="#036EB8"/>
<stop offset="1" stop-color="#469196"/>
</linearGradient>
<clipPath id="clip0">
<rect width="128" height="128" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

BIN
assets/jdlt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -0,0 +1,13 @@
import {Ctx} from "blitz"
import db from "db"
export default async function currentUserQuery(_ = null, {session}: Ctx) {
if (!session.userId) return null
const user = await db.user.findFirst({
where: {id: session.userId},
select: {id: true, name: true, email: true, role: true},
})
return user
}

View File

@@ -16,6 +16,9 @@ module.exports = withBundleAnalyzer({
cli: {
clearConsoleOnBlitzDev: false,
},
codegen: {
templateDir: "./my-templates",
},
log: {
// level: "trace",
},

View File

@@ -4,7 +4,6 @@
* and then export it. That way you can import here and anywhere else
* and use it straight away.
*/
import previewEmail from "preview-email"
type ResetPasswordMailer = {
to: string
@@ -38,6 +37,7 @@ export function forgotPasswordMailer({to, token}: ResetPasswordMailer) {
throw new Error("No production email implementation in mailers/forgotPasswordMailer")
} else {
// Preview email in the browser
const previewEmail = (await import("preview-email")).default
await previewEmail(msg)
}
},

View File

@@ -5,6 +5,7 @@
"dev": "blitz dev",
"build": "blitz build",
"start": "blitz start",
"console": "blitz console",
"studio": "blitz prisma studio",
"lint": "eslint --ignore-path .gitignore --ext .js,.ts,.tsx .",
"analyze": "cross-env ANALYZE=true blitz build",
@@ -29,7 +30,7 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.42.4",
"blitz": "0.45.4",
"final-form": "4.20.1",
"passport-auth0": "1.4.0",
"passport-github2": "0.1.12",

View File

@@ -1,8 +1,9 @@
import {Link, BlitzPage, useMutation} from "blitz"
import {Link, BlitzPage, useMutation, Image} from "blitz"
import Layout from "app/layouts/Layout"
import logout from "app/auth/mutations/logout"
import {useCurrentUser} from "app/hooks/useCurrentUser"
import {Suspense} from "react"
import logo from "public/logo.png"
/*
* This file is just for a pleasant getting started page for your new app.
@@ -54,7 +55,7 @@ const Home: BlitzPage = () => {
<div className="container">
<main>
<div className="logo">
<img src="/logo.png" alt="blitz.js" />
<Image src={logo} alt="blitz.js" />
</div>
<p>
<strong>Congrats!</strong> Your app is ready, including user sign-up and log-in.

View File

@@ -4,8 +4,7 @@
* This seed function is executed when you run `blitz db seed`.
*
* Probably you want to use a library like https://chancejs.com
* or https://github.com/Marak/Faker.js to easily generate
* realistic data.
* to easily generate realistic data.
*/
const seed = async () => {
// for (let i = 0; i < 5; i++) {

View File

@@ -31,7 +31,7 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.42.4",
"blitz": "0.45.4",
"final-form": "4.20.1",
"prisma": "2.24.1",
"react": "0.0.0-experimental-6a589ad71",

View File

@@ -1,7 +1,7 @@
import blitz from "blitz/custom-server"
import {createServer} from "http"
import {parse} from "url"
import {log} from "@blitzjs/display"
import {log} from "next/dist/server/lib/logging"
const {PORT = "3000"} = process.env
const dev = process.env.NODE_ENV !== "production"

View File

@@ -1,5 +1,7 @@
process.env.NODE_ENV = "test"
require("dotenv-flow").config({ silent: true })
import { loadEnvConfig } from "@blitzjs/env"
loadEnvConfig()
import "./register-ts-paths"
import db from "db"

View File

@@ -59,7 +59,7 @@ model Token {
// NOTE: It's highly recommended to use an enum for the token type
// but enums only work in Postgres.
// See: https://blitzjs.com/docs/database-overview#switch-to-postgresql
// See: https://blitzjs.com/docs/database-overview#switch-to-postgre-sql
// enum TokenType {
// RESET_PASSWORD
// }

View File

@@ -4,8 +4,7 @@
* This seed function is executed when you run `blitz db seed`.
*
* Probably you want to use a library like https://chancejs.com
* or https://github.com/Marak/Faker.js to easily generate
* realistic data.
* to easily generate realistic data.
*/
const seed = async () => {
// for (let i = 0; i < 5; i++) {

View File

@@ -4,7 +4,6 @@
* and then export it. That way you can import here and anywhere else
* and use it straight away.
*/
import previewEmail from "preview-email"
type ResetPasswordMailer = {
to: string
@@ -38,6 +37,7 @@ export function forgotPasswordMailer({ to, token }: ResetPasswordMailer) {
throw new Error("No production email implementation in mailers/forgotPasswordMailer")
} else {
// Preview email in the browser
const previewEmail = (await import("preview-email")).default
await previewEmail(msg)
}
},

View File

@@ -34,7 +34,7 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.42.4",
"blitz": "0.45.4",
"final-form": "4.20.1",
"react": "0.0.0-experimental-6a589ad71",
"react-dom": "0.0.0-experimental-6a589ad71",

View File

@@ -4,8 +4,7 @@
* This seed function is executed when you run `blitz db seed`.
*
* Probably you want to use a library like https://chancejs.com
* or https://github.com/Marak/Faker.js to easily generate
* realistic data.
* to easily generate realistic data.
*/
const seed = async () => {
// for (let i = 0; i < 5; i++) {

View File

@@ -28,7 +28,7 @@
]
},
"dependencies": {
"blitz": "0.42.4",
"blitz": "0.45.4",
"final-form": "4.20.1",
"graphql": "15.5.0",
"graphql-request": "3.4.0",

View File

@@ -3,4 +3,6 @@
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import "@testing-library/jest-dom/extend-expect"
require("dotenv-flow").config({ silent: true })
import { loadEnvConfig } from "@blitzjs/env"
loadEnvConfig()

View File

@@ -4,7 +4,7 @@ This example shows how to use [next-rosetta](https://www.npmjs.com/package/next-
## Getting started
### Install dependecies
### Install dependencies
```
# with npm

View File

@@ -3,7 +3,7 @@ import { LabeledTextField } from "app/core/components/LabeledTextField"
import { Form, FORM_ERROR } from "app/core/components/Form"
import login from "app/auth/mutations/login"
import { Login } from "app/auth/validations"
import { useI18n, I18nProps } from "next-rosetta"
import { useI18n } from "next-rosetta"
import type { MyLocale } from "app/core/i18n"
type LoginFormProps = {

View File

@@ -59,7 +59,7 @@ model Token {
// NOTE: It's highly recommended to use an enum for the token type
// but enums only work in Postgres.
// See: https://blitzjs.com/docs/database-overview#switch-to-postgresql
// See: https://blitzjs.com/docs/database-overview#switch-to-postgre-sql
// enum TokenType {
// RESET_PASSWORD
// }

View File

@@ -4,8 +4,7 @@
* This seed function is executed when you run `blitz db seed`.
*
* Probably you want to use a library like https://chancejs.com
* or https://github.com/Marak/Faker.js to easily generate
* realistic data.
* to easily generate realistic data.
*/
const seed = async () => {
// for (let i = 0; i < 5; i++) {

View File

@@ -4,7 +4,6 @@
* and then export it. That way you can import here and anywhere else
* and use it straight away.
*/
import previewEmail from "preview-email"
type ResetPasswordMailer = {
to: string
@@ -38,6 +37,7 @@ export function forgotPasswordMailer({ to, token }: ResetPasswordMailer) {
throw new Error("No production email implementation in mailers/forgotPasswordMailer")
} else {
// Preview email in the browser
const previewEmail = (await import("preview-email")).default
await previewEmail(msg)
}
},

View File

@@ -26,7 +26,7 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.42.4",
"blitz": "0.45.4",
"final-form": "4.20.1",
"next-rosetta": "1.3.1",
"react": "0.0.0-experimental-6a589ad71",

View File

@@ -26,7 +26,7 @@
]
},
"dependencies": {
"blitz": "0.42.4",
"blitz": "0.45.4",
"knex": "0.21.16",
"react": "0.0.0-experimental-6a589ad71",
"react-dom": "0.0.0-experimental-6a589ad71",

View File

@@ -33,7 +33,7 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.42.4",
"blitz": "0.45.4",
"prisma": "2.24.1",
"react": "0.0.0-experimental-6a589ad71",
"react-dom": "0.0.0-experimental-6a589ad71"

View File

@@ -1,12 +1,13 @@
import { BlitzPage } from "blitz"
import { BlitzPage, Image } from "blitz"
import Layout from "app/core/layouts/Layout"
import logo from "public/logo.png"
const Home: BlitzPage = () => {
return (
<div className="container">
<main>
<div className="logo">
<img src="/logo.png" alt="blitz.js" />
<Image src={logo} alt="blitz.js" />
</div>
<p>
<strong>Congrats!</strong> Your static app is ready.

View File

@@ -33,7 +33,7 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.42.4",
"blitz": "0.45.4",
"final-form": "4.20.1",
"prisma": "2.24.1",
"react": "0.0.0-experimental-6a589ad71",

View File

@@ -21,7 +21,7 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.42.4",
"blitz": "0.45.4",
"final-form": "4.20.1",
"prisma": "2.24.1",
"react": "0.0.0-experimental-6a589ad71",

View File

@@ -1,5 +1,5 @@
{
"version": "0.43.0",
"version": "0.45.4",
"packages": ["packages/*"],
"npmClient": "yarn",
"useWorkspaces": true,

View File

@@ -12,6 +12,7 @@
"dev": "lerna run dev --stream --parallel",
"dev2": "while true; do yarn --check-files && yarn dev; done",
"testonly": "jest --runInBand",
"testonly:packages": "ultra -r --filter \"packages/*\" --concurrency 15 test",
"testheadless": "cross-env HEADLESS=true yarn testonly",
"testsafari": "cross-env BROWSER_NAME=safari yarn testonly",
"testfirefox": "cross-env BROWSER_NAME=firefox yarn testonly",
@@ -60,8 +61,8 @@
"@types/passport": "1.0.5",
"@types/sharp": "0.28.4",
"@types/string-hash": "1.1.1",
"@typescript-eslint/eslint-plugin": "4.20.0",
"@typescript-eslint/parser": "^4.20.0",
"@typescript-eslint/eslint-plugin": "^5.5.0",
"@typescript-eslint/parser": "^5.5.0",
"@vercel/fetch": "6.1.1",
"@zeit/next-css": "1.0.2-canary.2",
"@zeit/next-sass": "1.0.2-canary.2",
@@ -110,7 +111,7 @@
"lost": "8.3.1",
"minimatch": "3.0.4",
"moment": "^2.24.0",
"node-fetch": "2.6.1",
"node-fetch": "2.6.7",
"node-notifier": "5.4.0",
"node-sass": "5.0.0",
"npm-run-all": "4.1.5",
@@ -144,7 +145,8 @@
"tailwindcss": "1.1.3",
"taskr": "1.1.0",
"tree-kill": "1.2.2",
"typescript": "4.4.2",
"typescript": "4.5.2",
"ultra-runner": "3.10.5",
"wait-port": "0.2.2",
"web-streams-polyfill": "2.1.1",
"webpack-bundle-analyzer": "4.3.0",

View File

@@ -42,8 +42,8 @@
"got": "10.7.0",
"prompts": "2.1.0",
"rimraf": "3.0.0",
"tar": "6.1.11",
"typescript": "4.3.4",
"tar": "4.4.18",
"typescript": "4.5.2",
"update-check": "1.5.4",
"validate-npm-package-name": "3.0.0"
},

View File

@@ -1,6 +1,6 @@
{
"name": "eslint-config-blitz",
"version": "0.43.0",
"version": "0.45.4",
"description": "Blitz.js eslint config",
"main": "index.js",
"license": "MIT",
@@ -11,8 +11,8 @@
"dependencies": {
"@next/eslint-plugin-next": "11.1.0",
"@rushstack/eslint-patch": "^1.0.6",
"@typescript-eslint/eslint-plugin": "4.20.0",
"@typescript-eslint/parser": "^4.20.0",
"@typescript-eslint/eslint-plugin": "^5.5.0",
"@typescript-eslint/parser": "^5.5.0",
"eslint-import-resolver-node": "^0.3.4",
"eslint-import-resolver-typescript": "^2.4.0",
"eslint-plugin-import": "^2.22.1",

View File

@@ -0,0 +1,3 @@
module.exports = {
preset: '../../../jest-unit.config.js',
}

View File

@@ -1,6 +1,6 @@
{
"name": "@blitzjs/installer",
"version": "0.43.0",
"version": "0.45.4",
"description": "Package installation for the Blitz CLI",
"homepage": "https://github.com/blitz-js/blitz#readme",
"license": "MIT",
@@ -30,10 +30,9 @@
"dependencies": {
"@babel/core": "7.12.10",
"@babel/plugin-transform-typescript": "7.12.1",
"@blitzjs/display": "0.43.0",
"@blitzjs/generator": "0.43.0",
"@mrleebo/prisma-ast": "0.2.4",
"@prisma/sdk": "2.19.0",
"@blitzjs/generator": "0.45.4",
"@mrleebo/prisma-ast": "0.2.6",
"@prisma/sdk": "3.9.1",
"@types/jscodeshift": "0.11.2",
"ast-types": "0.14.2",
"cross-spawn": "7.0.3",

View File

@@ -0,0 +1,12 @@
import { Text } from 'ink'
import * as React from 'react'
import { Newline } from './newline'
export const EnterToContinue: React.FC<{ message?: string }> = ({
message = 'Press ENTER to continue',
}) => (
<>
<Newline />
<Text bold>{message}</Text>
</>
)

View File

@@ -0,0 +1,6 @@
import { Box } from 'ink'
import * as React from 'react'
export const Newline: React.FC<{ count?: number }> = ({ count = 1 }) => {
return <Box paddingBottom={count} />
}

View File

@@ -1,14 +1,19 @@
import {spawn} from "cross-spawn"
import * as fs from "fs-extra"
import {Box, Text} from "ink"
import Spinner from "ink-spinner"
import * as path from "path"
import * as React from "react"
import {Newline} from "../components/newline"
import {RecipeCLIArgs} from "../types"
import {useEnterToContinue} from "../utils/use-enter-to-continue"
import {useUserInput} from "../utils/use-user-input"
import {Executor, executorArgument, ExecutorConfig, getExecutorArgument} from "./executor"
import { spawn } from 'cross-spawn'
import * as fs from 'fs-extra'
import { Box, Text } from 'ink'
import Spinner from 'ink-spinner'
import * as path from 'path'
import * as React from 'react'
import { Newline } from '../components/newline'
import { RecipeCLIArgs } from '../types'
import { useEnterToContinue } from '../utils/use-enter-to-continue'
import { useUserInput } from '../utils/use-user-input'
import {
Executor,
executorArgument,
ExecutorConfig,
getExecutorArgument,
} from './executor'
interface NpmPackage {
name: string
@@ -22,24 +27,26 @@ export interface Config extends ExecutorConfig {
packages: executorArgument<NpmPackage[]>
}
export function isAddDependencyExecutor(executor: ExecutorConfig): executor is Config {
export function isAddDependencyExecutor(
executor: ExecutorConfig
): executor is Config {
return (executor as Config).packages !== undefined
}
export const type = "add-dependency"
export const type = 'add-dependency'
function Package({pkg, loading}: {pkg: NpmPackage; loading: boolean}) {
function Package({ pkg, loading }: { pkg: NpmPackage; loading: boolean }) {
return (
<Text>
{` `}
{loading ? <Spinner /> : "📦"}
{loading ? <Spinner /> : '📦'}
{` ${pkg.name}@${pkg.version}`}
</Text>
)
}
const DependencyList = ({
lede = "Hang tight! Installing dependencies...",
lede = 'Hang tight! Installing dependencies...',
depsLoading = false,
devDepsLoading = false,
packages,
@@ -60,7 +67,9 @@ const DependencyList = ({
<Package key={pkg.name} pkg={pkg} loading={depsLoading} />
))}
<Newline />
{devPackages.length ? <Text>Dev Dependencies to be installed:</Text> : null}
{devPackages.length ? (
<Text>Dev Dependencies to be installed:</Text>
) : null}
{devPackages.map((pkg) => (
<Package key={pkg.name} pkg={pkg} loading={devDepsLoading} />
))}
@@ -72,10 +81,10 @@ const DependencyList = ({
* Exported for unit testing purposes
*/
export function getPackageManager() {
if (fs.existsSync(path.resolve("yarn.lock"))) {
return "yarn"
if (fs.existsSync(path.resolve('yarn.lock'))) {
return 'yarn'
}
return "npm"
return 'npm'
}
/**
@@ -83,40 +92,46 @@ export function getPackageManager() {
*/
export async function installPackages(packages: NpmPackage[], isDev = false) {
const packageManager = getPackageManager()
const isNPM = packageManager === "npm"
const pkgInstallArg = isNPM ? "install" : "add"
const isNPM = packageManager === 'npm'
const pkgInstallArg = isNPM ? 'install' : 'add'
const args: string[] = [pkgInstallArg]
if (isDev) {
args.push(isNPM ? "--save-dev" : "-D")
args.push(isNPM ? '--save-dev' : '-D')
}
packages.forEach((pkg) => {
pkg.version ? args.push(`${pkg.name}@${pkg.version}`) : args.push(pkg.name)
})
await new Promise((resolve) => {
const cp = spawn(packageManager, args, {
stdio: ["inherit", "pipe", "pipe"],
stdio: ['inherit', 'pipe', 'pipe'],
})
cp.on("exit", resolve)
cp.on('exit', resolve)
})
}
export const Commit: Executor["Commit"] = ({cliArgs, cliFlags, step, onChangeCommitted}) => {
export const Commit: Executor['Commit'] = ({
cliArgs,
cliFlags,
step,
onChangeCommitted,
}) => {
const userInput = useUserInput(cliFlags)
const [depsInstalled, setDepsInstalled] = React.useState(false)
const [devDepsInstalled, setDevDepsInstalled] = React.useState(false)
const handleChangeCommitted = React.useCallback(() => {
const packages = (step as Config).packages
const dependencies = packages.length === 1 ? "dependency" : "dependencies"
const dependencies = packages.length === 1 ? 'dependency' : 'dependencies'
onChangeCommitted(`Installed ${packages.length} ${dependencies}`)
}, [onChangeCommitted, step])
React.useEffect(() => {
async function installDeps() {
const packagesToInstall = getExecutorArgument((step as Config).packages, cliArgs).filter(
(p) => !p.isDevDep,
)
const packagesToInstall = getExecutorArgument(
(step as Config).packages,
cliArgs
).filter((p) => !p.isDevDep)
await installPackages(packagesToInstall)
setDepsInstalled(true)
}
@@ -127,9 +142,10 @@ export const Commit: Executor["Commit"] = ({cliArgs, cliFlags, step, onChangeCom
React.useEffect(() => {
if (!depsInstalled) return
async function installDevDeps() {
const packagesToInstall = getExecutorArgument((step as Config).packages, cliArgs).filter(
(p) => p.isDevDep,
)
const packagesToInstall = getExecutorArgument(
(step as Config).packages,
cliArgs
).filter((p) => p.isDevDep)
await installPackages(packagesToInstall, true)
setDevDepsInstalled(true)
}
@@ -186,7 +202,12 @@ const CommitWithInput = ({
)
}
const CommitWithoutInput = ({depsInstalled, devDepsInstalled, step, cliArgs}: CommitChildProps) => (
const CommitWithoutInput = ({
depsInstalled,
devDepsInstalled,
step,
cliArgs,
}: CommitChildProps) => (
<DependencyList
depsLoading={!depsInstalled}
devDepsLoading={!devDepsInstalled}

View File

@@ -1,7 +1,7 @@
import {Box, Text} from "ink"
import * as React from "react"
import {Newline} from "../components/newline"
import {RecipeCLIArgs, RecipeCLIFlags} from "../types"
import { Box, Text } from 'ink'
import * as React from 'react'
import { Newline } from '../components/newline'
import { RecipeCLIArgs, RecipeCLIFlags } from '../types'
export interface ExecutorConfig {
successIcon?: string
@@ -32,16 +32,16 @@ export interface Executor {
type dynamicExecutorArgument<T> = (cliArgs: RecipeCLIArgs) => T
function isDynamicExecutorArgument<T>(
input: executorArgument<T>,
input: executorArgument<T>
): input is dynamicExecutorArgument<T> {
return typeof (input as dynamicExecutorArgument<T>) === "function"
return typeof (input as dynamicExecutorArgument<T>) === 'function'
}
export type executorArgument<T> = T | dynamicExecutorArgument<T>
export function Frontmatter({executor}: {executor: ExecutorConfig}) {
export function Frontmatter({ executor }: { executor: ExecutorConfig }) {
const lineLength = executor.stepName.length + 6
const verticalBorder = `+${new Array(lineLength).fill("").join("")}+`
const verticalBorder = `+${new Array(lineLength).fill('').join('')}+`
return (
<Box flexDirection="column" paddingBottom={1}>
<Newline />
@@ -63,7 +63,10 @@ export function Frontmatter({executor}: {executor: ExecutorConfig}) {
)
}
export function getExecutorArgument<T>(input: executorArgument<T>, cliArgs: RecipeCLIArgs): T {
export function getExecutorArgument<T>(
input: executorArgument<T>,
cliArgs: RecipeCLIArgs
): T {
if (isDynamicExecutorArgument(input)) {
return input(cliArgs)
}

View File

@@ -1,5 +1,5 @@
import {prompt as enquirer} from "enquirer"
import globby from "globby"
import { prompt as enquirer } from 'enquirer'
import globby from 'globby'
enum SearchType {
file,
@@ -13,8 +13,8 @@ interface FilePromptOptions {
context: any
}
function getMatchingFiles(filter: string = ""): Promise<string[]> {
return globby(filter, {expandDirectories: true})
function getMatchingFiles(filter: string = ''): Promise<string[]> {
return globby(filter, { expandDirectories: true })
}
export async function filePrompt(options: FilePromptOptions): Promise<string> {
@@ -24,10 +24,10 @@ export async function filePrompt(options: FilePromptOptions): Promise<string> {
if (choices.length === 1) {
return choices[0]
}
const results: {file: string} = await enquirer({
type: "autocomplete",
name: "file",
message: "Select the target file",
const results: { file: string } = await enquirer({
type: 'autocomplete',
name: 'file',
message: 'Select the target file',
// @ts-ignore
limit: 10,
choices,

View File

@@ -1,10 +1,10 @@
import {createPatch} from "diff"
import * as fs from "fs-extra"
import {Box, Text} from "ink"
import Spinner from "ink-spinner"
import * as React from "react"
import {EnterToContinue} from "../components/enter-to-continue"
import {RecipeCLIArgs} from "../types"
import { createPatch } from 'diff'
import * as fs from 'fs-extra'
import { Box, Text } from 'ink'
import Spinner from 'ink-spinner'
import * as React from 'react'
import { EnterToContinue } from '../components/enter-to-continue'
import { RecipeCLIArgs } from '../types'
import {
processFile,
stringProcessFile,
@@ -12,11 +12,16 @@ import {
transform,
Transformer,
TransformStatus,
} from "../utils/transform"
import {useEnterToContinue} from "../utils/use-enter-to-continue"
import {useUserInput} from "../utils/use-user-input"
import {Executor, executorArgument, ExecutorConfig, getExecutorArgument} from "./executor"
import {filePrompt} from "./file-prompt"
} from '../utils/transform'
import { useEnterToContinue } from '../utils/use-enter-to-continue'
import { useUserInput } from '../utils/use-user-input'
import {
Executor,
executorArgument,
ExecutorConfig,
getExecutorArgument,
} from './executor'
import { filePrompt } from './file-prompt'
export interface Config extends ExecutorConfig {
selectTargetFiles?(cliArgs: RecipeCLIArgs): any[]
@@ -25,19 +30,26 @@ export interface Config extends ExecutorConfig {
transformPlain?: StringTransformer
}
export function isFileTransformExecutor(executor: ExecutorConfig): executor is Config {
export function isFileTransformExecutor(
executor: ExecutorConfig
): executor is Config {
return (
(executor as Config).transform !== undefined ||
(executor as Config).transformPlain !== undefined
)
}
export const type = "file-transform"
export const Propose: Executor["Propose"] = ({cliArgs, cliFlags, onProposalAccepted, step}) => {
export const type = 'file-transform'
export const Propose: Executor['Propose'] = ({
cliArgs,
cliFlags,
onProposalAccepted,
step,
}) => {
const userInput = useUserInput(cliFlags)
const [diff, setDiff] = React.useState<string | null>(null)
const [error, setError] = React.useState<Error | null>(null)
const [filePath, setFilePath] = React.useState("")
const [filePath, setFilePath] = React.useState('')
const [proposalAccepted, setProposalAccepted] = React.useState(false)
const acceptProposal = React.useCallback(() => {
@@ -49,11 +61,14 @@ export const Propose: Executor["Propose"] = ({cliArgs, cliFlags, onProposalAccep
async function generateDiff() {
const fileToTransform: string = await filePrompt({
context: cliArgs,
globFilter: getExecutorArgument((step as Config).singleFileSearch, cliArgs),
globFilter: getExecutorArgument(
(step as Config).singleFileSearch,
cliArgs
),
getChoices: (step as Config).selectTargetFiles,
})
setFilePath(fileToTransform)
const originalFile = fs.readFileSync(fileToTransform).toString("utf-8")
const originalFile = fs.readFileSync(fileToTransform).toString('utf-8')
const newFile = await ((step as Config).transformPlain
? stringProcessFile(originalFile, (step as Config).transformPlain!)
: processFile(originalFile, (step as Config).transform!))
@@ -96,19 +111,19 @@ interface ProposeChildProps {
acceptProposal: () => void
}
const Diff = ({diff}: {diff: string}) => (
const Diff = ({ diff }: { diff: string }) => (
<>
{diff
.split("\n")
.split('\n')
.slice(2)
.map((line, idx) => {
let styleProps: any = {}
if (line.startsWith("-") && !line.startsWith("---")) {
if (line.startsWith('-') && !line.startsWith('---')) {
styleProps.bold = true
styleProps.color = "red"
} else if (line.startsWith("+") && !line.startsWith("+++")) {
styleProps.color = 'red'
} else if (line.startsWith('+') && !line.startsWith('+++')) {
styleProps.bold = true
styleProps.color = "green"
styleProps.color = 'green'
}
return (
<Text {...styleProps} key={idx}>
@@ -125,7 +140,7 @@ const ProposeWithInput = ({
proposalAccepted,
acceptProposal,
}: ProposeChildProps) => {
useEnterToContinue(acceptProposal, filePath !== "" && !proposalAccepted)
useEnterToContinue(acceptProposal, filePath !== '' && !proposalAccepted)
return (
<Box flexDirection="column">
@@ -142,7 +157,7 @@ const ProposeWithoutInput = ({
acceptProposal,
}: ProposeChildProps) => {
React.useEffect(() => {
if (filePath !== "" && !proposalAccepted) {
if (filePath !== '' && !proposalAccepted) {
acceptProposal()
}
}, [acceptProposal, filePath, proposalAccepted])
@@ -154,7 +169,11 @@ const ProposeWithoutInput = ({
)
}
export const Commit: Executor["Commit"] = ({onChangeCommitted, proposalData: filePath, step}) => {
export const Commit: Executor['Commit'] = ({
onChangeCommitted,
proposalData: filePath,
step,
}) => {
React.useEffect(() => {
void (async function () {
const results = await transform(
@@ -162,7 +181,7 @@ export const Commit: Executor["Commit"] = ({onChangeCommitted, proposalData: fil
await ((step as Config).transformPlain
? stringProcessFile(original, (step as Config).transformPlain!)
: processFile(original, (step as Config).transform!)),
[filePath],
[filePath]
)
if (results.some((r) => r.status === TransformStatus.Failure)) {
console.error(results)

View File

@@ -1,24 +1,31 @@
import {Generator, GeneratorOptions, SourceRootType} from "@blitzjs/generator"
import {Box, Text} from "ink"
import {useEffect, useState} from "react"
import * as React from "react"
import {EnterToContinue} from "../components/enter-to-continue"
import {useEnterToContinue} from "../utils/use-enter-to-continue"
import {useUserInput} from "../utils/use-user-input"
import {Executor, executorArgument, ExecutorConfig, getExecutorArgument} from "./executor"
import { Generator, GeneratorOptions, SourceRootType } from '@blitzjs/generator'
import { Box, Text } from 'ink'
import { useEffect, useState } from 'react'
import * as React from 'react'
import { EnterToContinue } from '../components/enter-to-continue'
import { useEnterToContinue } from '../utils/use-enter-to-continue'
import { useUserInput } from '../utils/use-user-input'
import {
Executor,
executorArgument,
ExecutorConfig,
getExecutorArgument,
} from './executor'
export interface Config extends ExecutorConfig {
targetDirectory?: executorArgument<string>
templatePath: executorArgument<string>
templateValues: executorArgument<{[key: string]: string}>
templateValues: executorArgument<{ [key: string]: string }>
destinationPathPrompt?: executorArgument<string>
}
export function isNewFileExecutor(executor: ExecutorConfig): executor is Config {
export function isNewFileExecutor(
executor: ExecutorConfig
): executor is Config {
return (executor as Config).templatePath !== undefined
}
export const type = "new-file"
export const type = 'new-file'
interface TempGeneratorOptions extends GeneratorOptions {
targetDirectory?: string
@@ -34,9 +41,9 @@ class TempGenerator extends Generator<TempGeneratorOptions> {
constructor(options: TempGeneratorOptions) {
super(options)
this.sourceRoot = {type: "absolute", path: options.templateRoot}
this.sourceRoot = { type: 'absolute', path: options.templateRoot }
this.templateValues = options.templateValues
this.targetDirectory = options.targetDirectory || "."
this.targetDirectory = options.targetDirectory || '.'
}
getTemplateValues() {
@@ -48,26 +55,37 @@ class TempGenerator extends Generator<TempGeneratorOptions> {
}
}
export const Commit: Executor["Commit"] = ({cliArgs, cliFlags, onChangeCommitted, step}) => {
export const Commit: Executor['Commit'] = ({
cliArgs,
cliFlags,
onChangeCommitted,
step,
}) => {
const userInput = useUserInput(cliFlags)
const generatorArgs = React.useMemo(
() => ({
destinationRoot: ".",
targetDirectory: getExecutorArgument((step as Config).targetDirectory, cliArgs),
destinationRoot: '.',
targetDirectory: getExecutorArgument(
(step as Config).targetDirectory,
cliArgs
),
templateRoot: getExecutorArgument((step as Config).templatePath, cliArgs),
templateValues: getExecutorArgument((step as Config).templateValues, cliArgs),
templateValues: getExecutorArgument(
(step as Config).templateValues,
cliArgs
),
}),
[cliArgs, step],
[cliArgs, step]
)
const [fileCreateOutput, setFileCreateOutput] = useState("")
const [fileCreateOutput, setFileCreateOutput] = useState('')
const [changeCommited, setChangeCommited] = useState(false)
const fileCreateLines = fileCreateOutput.split("\n")
const fileCreateLines = fileCreateOutput.split('\n')
const handleChangeCommitted = React.useCallback(() => {
setChangeCommited(true)
onChangeCommitted(
`Successfully created ${fileCreateLines
.map((l) => l.split(" ").slice(1).join("").trim())
.join(", ")}`,
.map((l) => l.split(' ').slice(1).join('').trim())
.join(', ')}`
)
}, [fileCreateLines, onChangeCommitted])
@@ -104,11 +122,14 @@ const CommitWithInput = ({
fileCreateOutput,
handleChangeCommitted,
}: CommitChildProps) => {
useEnterToContinue(handleChangeCommitted, !changeCommited && fileCreateOutput !== "")
useEnterToContinue(
handleChangeCommitted,
!changeCommited && fileCreateOutput !== ''
)
return (
<Box flexDirection="column">
{fileCreateOutput !== "" && (
{fileCreateOutput !== '' && (
<>
<Text>{fileCreateOutput}</Text>
<EnterToContinue />
@@ -124,12 +145,14 @@ const CommitWithoutInput = ({
handleChangeCommitted,
}: CommitChildProps) => {
React.useEffect(() => {
if (!changeCommited && fileCreateOutput !== "") {
if (!changeCommited && fileCreateOutput !== '') {
handleChangeCommitted()
}
}, [changeCommited, fileCreateOutput, handleChangeCommitted])
return (
<Box flexDirection="column">{fileCreateOutput !== "" && <Text>{fileCreateOutput}</Text>}</Box>
<Box flexDirection="column">
{fileCreateOutput !== '' && <Text>{fileCreateOutput}</Text>}
</Box>
)
}

View File

@@ -1,24 +1,34 @@
import {Box, Text} from "ink"
import * as React from "react"
import {EnterToContinue} from "../components/enter-to-continue"
import {useEnterToContinue} from "../utils/use-enter-to-continue"
import {useUserInput} from "../utils/use-user-input"
import {Executor, executorArgument, ExecutorConfig, getExecutorArgument} from "./executor"
import { Box, Text } from 'ink'
import * as React from 'react'
import { EnterToContinue } from '../components/enter-to-continue'
import { useEnterToContinue } from '../utils/use-enter-to-continue'
import { useUserInput } from '../utils/use-user-input'
import {
Executor,
executorArgument,
ExecutorConfig,
getExecutorArgument,
} from './executor'
export interface Config extends ExecutorConfig {
message: executorArgument<string>
}
export const type = "print-message"
export const type = 'print-message'
export const Commit: Executor["Commit"] = ({cliArgs, cliFlags, onChangeCommitted, step}) => {
export const Commit: Executor['Commit'] = ({
cliArgs,
cliFlags,
onChangeCommitted,
step,
}) => {
const userInput = useUserInput(cliFlags)
const generatorArgs = React.useMemo(
() => ({
message: getExecutorArgument((step as Config).message, cliArgs),
stepName: getExecutorArgument((step as Config).stepName, cliArgs),
}),
[cliArgs, step],
[cliArgs, step]
)
const [changeCommited, setChangeCommited] = React.useState(false)
@@ -39,7 +49,7 @@ export const Commit: Executor["Commit"] = ({cliArgs, cliFlags, onChangeCommitted
interface CommitChildProps {
changeCommited: boolean
generatorArgs: {message: string; stepName: string}
generatorArgs: { message: string; stepName: string }
handleChangeCommitted: () => void
}

View File

@@ -0,0 +1,161 @@
import { spawn } from 'cross-spawn'
import { Box, Text } from 'ink'
import Spinner from 'ink-spinner'
import * as React from 'react'
import { Newline } from '../components/newline'
import { RecipeCLIArgs } from '../types'
import { useEnterToContinue } from '../utils/use-enter-to-continue'
import { useUserInput } from '../utils/use-user-input'
import { Executor, ExecutorConfig, getExecutorArgument } from './executor'
export type CliCommand = string | [string, ...string[]]
export interface Config extends ExecutorConfig {
command: CliCommand
}
export interface CommitChildProps {
commandInstalled: boolean
handleChangeCommitted: () => void
command: CliCommand
cliArgs: RecipeCLIArgs
step: Config
}
export const type = 'run-command'
function Command({
command,
loading,
}: {
command: CliCommand
loading: boolean
}) {
return (
<Text>
{` `}
{loading ? <Spinner /> : '✅'}
{` ${typeof command === 'string' ? command : command.join(' ')}`}
</Text>
)
}
const CommandList = ({
lede = 'Hang tight! Running...',
commandLoading = false,
step,
command,
}: {
lede?: string
commandLoading?: boolean
step: Config
command: CliCommand
}) => {
return (
<Box flexDirection="column">
<Text>{lede}</Text>
<Newline />
<Command key={step.stepId} command={command} loading={commandLoading} />
</Box>
)
}
/**
* INFO: Exported for unit testing purposes
*
* This function calls the defined command with their optional arguments if defined
*
* @param {CliCommand} input The Command and arguments
* @return Promise<void>
*
* @example await executeCommand("ls")
* @example await executeCommand(["ls"])
* @example await executeCommand(["ls", ...["-a", "-l"]])
*/
export async function executeCommand(input: CliCommand): Promise<void> {
// from https://stackoverflow.com/a/43766456/9950655
const argsRegex = /("[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*'|\/[^/\\]*(?:\\[\S\s][^/\\]*)*\/[gimy]*(?=\s|$)|(?:\\\s|\S)+)/g
const command: string[] = Array.isArray(input)
? input
: input.match(argsRegex) || []
if (command.length === 0) {
throw new Error(`The command is too short: \`${JSON.stringify(input)}\``)
}
await new Promise((resolve) => {
const cp = spawn(command[0], command.slice(1), {
stdio: ['inherit', 'pipe', 'pipe'],
})
cp.on('exit', resolve)
})
}
export const Commit: Executor['Commit'] = ({
cliArgs,
cliFlags,
step,
onChangeCommitted,
}) => {
const userInput = useUserInput(cliFlags)
const [commandInstalled, setCommandInstalled] = React.useState(false)
const executorCommand = getExecutorArgument((step as Config).command, cliArgs)
const handleChangeCommitted = React.useCallback(() => {
onChangeCommitted(`Executed command ${executorCommand}`)
}, [executorCommand, onChangeCommitted])
React.useEffect(() => {
async function runCommand() {
await executeCommand(executorCommand)
setCommandInstalled(true)
}
// eslint-disable-next-line @typescript-eslint/no-floating-promises
runCommand()
}, [cliArgs, step, executorCommand])
React.useEffect(() => {
if (commandInstalled) {
handleChangeCommitted()
}
}, [commandInstalled, handleChangeCommitted])
const childProps: CommitChildProps = {
commandInstalled,
handleChangeCommitted,
command: executorCommand,
cliArgs,
step: step as Config,
}
if (userInput) return <CommitWithInput {...childProps} />
else return <CommitWithoutInput {...childProps} />
}
const CommitWithInput = ({
commandInstalled,
handleChangeCommitted,
command,
step,
}: CommitChildProps) => {
useEnterToContinue(handleChangeCommitted, commandInstalled)
return (
<CommandList
commandLoading={!commandInstalled}
step={step}
command={command}
/>
)
}
const CommitWithoutInput = ({
commandInstalled,
command,
step,
}: CommitChildProps) => (
<CommandList
commandLoading={!commandInstalled}
step={step}
command={command}
/>
)

View File

@@ -0,0 +1,12 @@
export * from './recipe-executor'
export * from './recipe-builder'
export * from './executors/executor'
export { type as AddDependencyType } from './executors/add-dependency-executor'
export { type as FileTransformType } from './executors/file-transform-executor'
export { type as NewFileType } from './executors/new-file-executor'
export { type as PrintMessageType } from './executors/print-message-executor'
export * from './utils/paths'
export * from './transforms'
export { customTsParser } from './utils/transform'
export type { Program, RecipeCLIArgs, RecipeCLIFlags } from './types'

View File

@@ -0,0 +1,97 @@
import * as AddDependencyExecutor from './executors/add-dependency-executor'
import * as TransformFileExecutor from './executors/file-transform-executor'
import * as NewFileExecutor from './executors/new-file-executor'
import * as PrintMessageExecutor from './executors/print-message-executor'
import * as RunCommandExecutor from './executors/run-command-executor'
import { ExecutorConfigUnion, RecipeExecutor } from './recipe-executor'
import { RecipeMeta } from './types'
export interface IRecipeBuilder {
setName(name: string): IRecipeBuilder
setDescription(description: string): IRecipeBuilder
printMessage(
step: Omit<Omit<PrintMessageExecutor.Config, 'stepType'>, 'explanation'>
): IRecipeBuilder
setOwner(owner: string): IRecipeBuilder
setRepoLink(repoLink: string): IRecipeBuilder
addAddDependenciesStep(
step: Omit<AddDependencyExecutor.Config, 'stepType'>
): IRecipeBuilder
addNewFilesStep(
step: Omit<NewFileExecutor.Config, 'stepType'>
): IRecipeBuilder
addTransformFilesStep(
step: Omit<TransformFileExecutor.Config, 'stepType'>
): IRecipeBuilder
addRunCommandStep(
step: Omit<RunCommandExecutor.Config, 'stepType'>
): IRecipeBuilder
build(): RecipeExecutor<any>
}
export function RecipeBuilder(): IRecipeBuilder {
const steps: ExecutorConfigUnion[] = []
const meta: Partial<RecipeMeta> = {}
return {
setName(name: string) {
meta.name = name
return this
},
setDescription(description: string) {
meta.description = description
return this
},
printMessage(step: Omit<PrintMessageExecutor.Config, 'stepType'>) {
steps.push({
stepType: PrintMessageExecutor.type,
...step,
})
return this
},
setOwner(owner: string) {
meta.owner = owner
return this
},
setRepoLink(repoLink: string) {
meta.repoLink = repoLink
return this
},
addAddDependenciesStep(
step: Omit<AddDependencyExecutor.Config, 'stepType'>
) {
steps.push({
stepType: AddDependencyExecutor.type,
...step,
})
return this
},
addNewFilesStep(step: Omit<NewFileExecutor.Config, 'stepType'>) {
steps.push({
stepType: NewFileExecutor.type,
...step,
})
return this
},
addTransformFilesStep(
step: Omit<TransformFileExecutor.Config, 'stepType'>
) {
steps.push({
stepType: TransformFileExecutor.type,
...step,
})
return this
},
addRunCommandStep(step: Omit<RunCommandExecutor.Config, 'stepType'>) {
steps.push({
stepType: RunCommandExecutor.type,
...step,
})
return this
},
build() {
return new RecipeExecutor(meta as RecipeMeta, steps)
},
}
}

View File

@@ -0,0 +1,52 @@
import { render } from 'ink'
import { baseLogger } from 'next/dist/server/lib/logging'
import React from 'react'
import * as AddDependencyExecutor from './executors/add-dependency-executor'
import * as FileTransformExecutor from './executors/file-transform-executor'
import * as NewFileExecutor from './executors/new-file-executor'
import * as PrintMessageExecutor from './executors/print-message-executor'
import { RecipeRenderer } from './recipe-renderer'
import { RecipeCLIArgs, RecipeCLIFlags, RecipeMeta } from './types'
// const debug = require('debug')("blitz:installer")
type ExecutorConfig =
| AddDependencyExecutor.Config
| FileTransformExecutor.Config
| NewFileExecutor.Config
| PrintMessageExecutor.Config
export type { ExecutorConfig as ExecutorConfigUnion }
export class RecipeExecutor<Options extends RecipeMeta> {
private readonly steps: ExecutorConfig[]
private readonly options: Options
constructor(options: Options, steps: ExecutorConfig[]) {
this.options = options
this.steps = steps
}
async run(
cliArgs: RecipeCLIArgs = {},
cliFlags: RecipeCLIFlags = { yesToAll: false }
): Promise<void> {
try {
const { waitUntilExit } = render(
<RecipeRenderer
cliArgs={cliArgs}
cliFlags={cliFlags}
steps={this.steps}
recipeMeta={this.options}
/>,
{ exitOnCtrlC: false }
)
await waitUntilExit()
baseLogger({ displayDateTime: false, displayLogLevel: false }).info(
`\n🎉 The ${this.options.name} recipe has been installed!\n`
)
} catch (e) {
baseLogger({ displayDateTime: false }).error(e as any)
return
}
}
}

View File

@@ -1,15 +1,16 @@
import {Box, Text, useApp, useInput} from "ink"
import React from "react"
import {EnterToContinue} from "./components/enter-to-continue"
import {Newline} from "./components/newline"
import * as AddDependencyExecutor from "./executors/add-dependency-executor"
import {Executor, ExecutorConfig, Frontmatter} from "./executors/executor"
import * as FileTransformExecutor from "./executors/file-transform-executor"
import * as NewFileExecutor from "./executors/new-file-executor"
import * as PrintMessageExecutor from "./executors/print-message-executor"
import {RecipeCLIArgs, RecipeCLIFlags, RecipeMeta} from "./types"
import {useEnterToContinue} from "./utils/use-enter-to-continue"
import {useUserInput} from "./utils/use-user-input"
import { Box, Text, useApp, useInput } from 'ink'
import React from 'react'
import { EnterToContinue } from './components/enter-to-continue'
import { Newline } from './components/newline'
import * as AddDependencyExecutor from './executors/add-dependency-executor'
import { Executor, ExecutorConfig, Frontmatter } from './executors/executor'
import * as FileTransformExecutor from './executors/file-transform-executor'
import * as NewFileExecutor from './executors/new-file-executor'
import * as PrintMessageExecutor from './executors/print-message-executor'
import * as RunCommandExecutor from './executors/run-command-executor'
import { RecipeCLIArgs, RecipeCLIFlags, RecipeMeta } from './types'
import { useEnterToContinue } from './utils/use-enter-to-continue'
import { useUserInput } from './utils/use-user-input'
enum Action {
SkipStep,
@@ -27,20 +28,26 @@ enum Status {
Committed,
}
const ExecutorMap: {[key: string]: Executor} = {
const ExecutorMap: { [key: string]: Executor } = {
[AddDependencyExecutor.type]: AddDependencyExecutor,
[NewFileExecutor.type]: NewFileExecutor,
[PrintMessageExecutor.type]: PrintMessageExecutor,
[FileTransformExecutor.type]: FileTransformExecutor,
[RunCommandExecutor.type]: RunCommandExecutor,
} as const
interface State {
steps: {executor: ExecutorConfig; status: Status; proposalData?: any; successMsg: string}[]
steps: {
executor: ExecutorConfig
status: Status
proposalData?: any
successMsg: string
}[]
current: number
}
function recipeReducer(state: State, action: {type: Action; data?: any}) {
const newState = {...state}
function recipeReducer(state: State, action: { type: Action; data?: any }) {
const newState = { ...state }
switch (action.type) {
case Action.ProposeChange:
newState.steps[newState.current].status = Status.Proposed
@@ -55,7 +62,10 @@ function recipeReducer(state: State, action: {type: Action; data?: any}) {
case Action.CompleteChange:
newState.steps[newState.current].status = Status.Committed
newState.steps[newState.current].successMsg = action.data as string
newState.current = Math.min(newState.current + 1, newState.steps.length - 1)
newState.current = Math.min(
newState.current + 1,
newState.steps.length - 1
)
break
case Action.SkipStep:
newState.current += 1
@@ -71,7 +81,9 @@ interface RecipeProps {
recipeMeta: RecipeMeta
}
const DispatchContext = React.createContext<React.Dispatch<{type: Action; data?: any}>>(() => {})
const DispatchContext = React.createContext<
React.Dispatch<{ type: Action; data?: any }>
>(() => {})
function WelcomeMessage({
recipeMeta,
@@ -101,16 +113,19 @@ function WelcomeMessage({
)
}
function StepMessages({state}: {state: State}) {
function StepMessages({ state }: { state: State }) {
const messages = state.steps
.map((step) => ({msg: step.successMsg, icon: step.executor.successIcon ?? "✅"}))
.map((step) => ({
msg: step.successMsg,
icon: step.executor.successIcon ?? '✅',
}))
.filter((s) => s.msg)
return (
<>
{messages.map(({msg, icon}, index) => (
{messages.map(({ msg, icon }, index) => (
<Text key={msg + index} color="green">
{msg === "\n" ? "" : icon} {msg}
{msg === '\n' ? '' : icon} {msg}
</Text>
))}
</>
@@ -130,30 +145,30 @@ function StepExecutor({
cliFlags: RecipeCLIFlags
proposalData?: any
}) {
const {Propose, Commit}: Executor = ExecutorMap[step.stepType]
const { Propose, Commit }: Executor = ExecutorMap[step.stepType]
const dispatch = React.useContext(DispatchContext)
const handleProposalAccepted = React.useCallback(
(msg) => {
dispatch({type: Action.CommitApproved, data: msg})
dispatch({ type: Action.CommitApproved, data: msg })
},
[dispatch],
[dispatch]
)
const handleChangeCommitted = React.useCallback(
(msg) => {
dispatch({type: Action.CompleteChange, data: msg})
dispatch({ type: Action.CompleteChange, data: msg })
},
[dispatch],
[dispatch]
)
React.useEffect(() => {
if (status === Status.Pending) {
dispatch({type: Action.ProposeChange})
dispatch({ type: Action.ProposeChange })
} else if (status === Status.ReadyToCommit) {
dispatch({type: Action.ApplyChange})
dispatch({ type: Action.ApplyChange })
}
if (status === Status.Proposed && !Propose) {
dispatch({type: Action.CommitApproved})
dispatch({ type: Action.CommitApproved })
}
}, [dispatch, status, Propose])
@@ -181,16 +196,25 @@ function StepExecutor({
)
}
export function RecipeRenderer({cliArgs, cliFlags, steps, recipeMeta}: RecipeProps) {
export function RecipeRenderer({
cliArgs,
cliFlags,
steps,
recipeMeta,
}: RecipeProps) {
const userInput = useUserInput(cliFlags)
const {exit} = useApp()
const { exit } = useApp()
const [state, dispatch] = React.useReducer(recipeReducer, {
current: userInput ? -1 : 0,
steps: steps.map((e) => ({executor: e, status: Status.Pending, successMsg: ""})),
steps: steps.map((e) => ({
executor: e,
status: Status.Pending,
successMsg: '',
})),
})
if (steps.length === 0) {
exit(new Error("This recipe has no steps"))
exit(new Error('This recipe has no steps'))
}
React.useEffect(() => {
@@ -228,18 +252,21 @@ function RecipeRendererWithInput({
cliFlags,
recipeMeta,
state,
}: Omit<RecipeProps, "steps"> & {state: State}) {
const {exit} = useApp()
}: Omit<RecipeProps, 'steps'> & { state: State }) {
const { exit } = useApp()
const dispatch = React.useContext(DispatchContext)
useInput((input, key) => {
if (input === "c" && key.ctrl) {
exit(new Error("You aborted installation"))
if (input === 'c' && key.ctrl) {
exit(new Error('You aborted installation'))
return
}
})
useEnterToContinue(() => dispatch({type: Action.SkipStep}), state.current === -1)
useEnterToContinue(
() => dispatch({ type: Action.SkipStep }),
state.current === -1
)
return (
<>
@@ -264,7 +291,7 @@ function RecipeRendererWithoutInput({
cliFlags,
recipeMeta,
state,
}: Omit<RecipeProps, "steps"> & {state: State}) {
}: Omit<RecipeProps, 'steps'> & { state: State }) {
return (
<>
<WelcomeMessage recipeMeta={recipeMeta} enterToContinue={false} />

View File

@@ -0,0 +1,35 @@
import type { ExpressionKind } from 'ast-types/gen/kinds'
import j from 'jscodeshift'
import { Program } from '../types'
import { transformBlitzConfig } from '.'
export const addBlitzMiddleware = (
program: Program,
middleware: ExpressionKind
): Program =>
transformBlitzConfig(program, (config) => {
// Locate the middleware property
const middlewareProp = config.properties.find(
(value) =>
value.type === 'ObjectProperty' &&
value.key.type === 'Identifier' &&
value.key.name === 'middleware'
) as j.ObjectProperty | undefined
if (middlewareProp && middlewareProp.value.type === 'ArrayExpression') {
// We found it, pop on our middleware.
middlewareProp.value.elements.push(middleware)
} else {
// No middleware prop, add our own.
config.properties.push(
j.property('init', j.identifier('middleware'), {
type: 'ArrayExpression',
elements: [middleware],
loc: null,
comments: null,
})
)
}
return config
})

View File

@@ -1,7 +1,10 @@
import j from "jscodeshift"
import {Program} from "../types"
import j from 'jscodeshift'
import { Program } from '../types'
export function addImport(program: Program, importToAdd: j.ImportDeclaration): Program {
export function addImport(
program: Program,
importToAdd: j.ImportDeclaration
): Program {
const importStatementCount = program.find(j.ImportDeclaration).length
if (importStatementCount === 0) {
program.find(j.Statement).at(0).insertBefore(importToAdd)

View File

@@ -0,0 +1,14 @@
import j from 'jscodeshift'
import { Program } from '../types'
export const findModuleExportsExpressions = (program: Program) =>
program.find(j.AssignmentExpression).filter((path) => {
const { left, right } = path.value
return (
left.type === 'MemberExpression' &&
left.object.type === 'Identifier' &&
left.property.type === 'Identifier' &&
left.property.name === 'exports' &&
right.type === 'ObjectExpression'
)
})

View File

@@ -0,0 +1,8 @@
export * from './add-import'
export * from './add-blitz-middleware'
export * from './find-module-exports-expressions'
export * from './prisma'
export * from './transform-blitz-config'
export * from './update-babel-config'
export * from './with-utilities'
export * from './wrap-blitz-config'

View File

@@ -1,5 +1,5 @@
import {Enum} from "@mrleebo/prisma-ast"
import {produceSchema} from "./produce-schema"
import { Enum } from '@mrleebo/prisma-ast'
import { produceSchema } from './produce-schema'
/**
* Adds an enum to your schema.prisma data model.
@@ -19,9 +19,14 @@ import {produceSchema} from "./produce-schema"
})
* ```
*/
export function addPrismaEnum(source: string, enumProps: Enum): Promise<string> {
export function addPrismaEnum(
source: string,
enumProps: Enum
): Promise<string> {
return produceSchema(source, (schema) => {
const existing = schema.list.find((x) => x.type === "enum" && x.name === enumProps.name)
const existing = schema.list.find(
(x) => x.type === 'enum' && x.name === enumProps.name
)
existing ? Object.assign(existing, enumProps) : schema.list.push(enumProps)
})
}

View File

@@ -1,5 +1,5 @@
import {Field, Model} from "@mrleebo/prisma-ast"
import {produceSchema} from "./produce-schema"
import { Field, Model } from '@mrleebo/prisma-ast'
import { produceSchema } from './produce-schema'
/**
* Adds a field to a model in your schema.prisma data model.
@@ -22,13 +22,19 @@ import {produceSchema} from "./produce-schema"
export function addPrismaField(
source: string,
modelName: string,
fieldProps: Field,
fieldProps: Field
): Promise<string> {
return produceSchema(source, (schema) => {
const model = schema.list.find((x) => x.type === "model" && x.name === modelName) as Model
const model = schema.list.find(
(x) => x.type === 'model' && x.name === modelName
) as Model
if (!model) return
const existing = model.properties.find((x) => x.type === "field" && x.name === fieldProps.name)
existing ? Object.assign(existing, fieldProps) : model.properties.push(fieldProps)
const existing = model.properties.find(
(x) => x.type === 'field' && x.name === fieldProps.name
)
existing
? Object.assign(existing, fieldProps)
: model.properties.push(fieldProps)
})
}

View File

@@ -1,5 +1,5 @@
import {Generator} from "@mrleebo/prisma-ast"
import {produceSchema} from "./produce-schema"
import { Generator } from '@mrleebo/prisma-ast'
import { produceSchema } from './produce-schema'
/**
* Adds a generator to your schema.prisma data model.
@@ -16,11 +16,16 @@ import {produceSchema} from "./produce-schema"
})
* ```
*/
export function addPrismaGenerator(source: string, generatorProps: Generator): Promise<string> {
export function addPrismaGenerator(
source: string,
generatorProps: Generator
): Promise<string> {
return produceSchema(source, (schema) => {
const existing = schema.list.find(
(x) => x.type === "generator" && x.name === generatorProps.name,
(x) => x.type === 'generator' && x.name === generatorProps.name
) as Generator
existing ? Object.assign(existing, generatorProps) : schema.list.push(generatorProps)
existing
? Object.assign(existing, generatorProps)
: schema.list.push(generatorProps)
})
}

View File

@@ -1,5 +1,5 @@
import {Model, ModelAttribute} from "@mrleebo/prisma-ast"
import {produceSchema} from "./produce-schema"
import { Model, ModelAttribute } from '@mrleebo/prisma-ast'
import { produceSchema } from './produce-schema'
/**
* Adds a field to a model in your schema.prisma data model.
@@ -22,16 +22,20 @@ import {produceSchema} from "./produce-schema"
export function addPrismaModelAttribute(
source: string,
modelName: string,
attributeProps: ModelAttribute,
attributeProps: ModelAttribute
): Promise<string> {
return produceSchema(source, (schema) => {
const model = schema.list.find((x) => x.type === "model" && x.name === modelName) as Model
const model = schema.list.find(
(x) => x.type === 'model' && x.name === modelName
) as Model
if (!model) return
const existing = model.properties.find(
(x) => x.type === "attribute" && x.name === attributeProps.name,
(x) => x.type === 'attribute' && x.name === attributeProps.name
)
existing ? Object.assign(existing, attributeProps) : model.properties.push(attributeProps)
existing
? Object.assign(existing, attributeProps)
: model.properties.push(attributeProps)
})
}

View File

@@ -1,5 +1,5 @@
import {Model} from "@mrleebo/prisma-ast"
import {produceSchema} from "./produce-schema"
import { Model } from '@mrleebo/prisma-ast'
import { produceSchema } from './produce-schema'
/**
* Adds an enum to your schema.prisma data model.
@@ -16,9 +16,16 @@ import {produceSchema} from "./produce-schema"
})
* ```
*/
export function addPrismaModel(source: string, modelProps: Model): Promise<string> {
export function addPrismaModel(
source: string,
modelProps: Model
): Promise<string> {
return produceSchema(source, (schema) => {
const existing = schema.list.find((x) => x.type === "model" && x.name === modelProps.name)
existing ? Object.assign(existing, modelProps) : schema.list.push(modelProps)
const existing = schema.list.find(
(x) => x.type === 'model' && x.name === modelProps.name
)
existing
? Object.assign(existing, modelProps)
: schema.list.push(modelProps)
})
}

View File

@@ -0,0 +1,7 @@
export * from './add-prisma-enum'
export * from './add-prisma-field'
export * from './add-prisma-generator'
export * from './add-prisma-model-attribute'
export * from './add-prisma-model'
export * from './produce-schema'
export * from './set-prisma-data-source'

View File

@@ -1,4 +1,4 @@
import {printSchema as printer, Schema} from "@mrleebo/prisma-ast"
import { printSchema as printer, Schema } from '@mrleebo/prisma-ast'
/**
* Takes the schema.prisma document parsed from @mrleebo/prisma-ast and

View File

@@ -1,4 +1,4 @@
import {getSchema, printSchema, Schema} from "@mrleebo/prisma-ast"
import { getSchema, printSchema, Schema } from '@mrleebo/prisma-ast'
/**
* A file transformer that parses a schema.prisma string, offers you a callback
@@ -11,7 +11,7 @@ import {getSchema, printSchema, Schema} from "@mrleebo/prisma-ast"
*/
export async function produceSchema(
source: string,
producer: (schema: Schema) => void,
producer: (schema: Schema) => void
): Promise<string> {
const schema = await getSchema(source)
producer(schema)

View File

@@ -1,5 +1,5 @@
import {Datasource} from "@mrleebo/prisma-ast"
import {produceSchema} from "./produce-schema"
import { Datasource } from '@mrleebo/prisma-ast'
import { produceSchema } from './produce-schema'
/**
* Modify the prisma datasource metadata to use the provider and url specified.
@@ -23,9 +23,14 @@ import {produceSchema} from "./produce-schema"
})
* ```
*/
export function setPrismaDataSource(source: string, datasourceProps: Datasource): Promise<string> {
export function setPrismaDataSource(
source: string,
datasourceProps: Datasource
): Promise<string> {
return produceSchema(source, (schema) => {
const existing = schema.list.find((x) => x.type === "datasource")
existing ? Object.assign(existing, datasourceProps) : schema.list.push(datasourceProps)
const existing = schema.list.find((x) => x.type === 'datasource')
existing
? Object.assign(existing, datasourceProps)
: schema.list.push(datasourceProps)
})
}

View File

@@ -1,25 +1,27 @@
import type {ExpressionKind} from "ast-types/gen/kinds"
import j from "jscodeshift"
import {Program} from "../types"
import type { ExpressionKind } from 'ast-types/gen/kinds'
import j from 'jscodeshift'
import { Program } from '../types'
function recursiveConfigSearch(
program: Program,
obj: ExpressionKind,
obj: ExpressionKind
): j.ObjectExpression | undefined {
// Identifier being a variable name
if (obj.type === "Identifier") {
const {node} = j(obj).get()
if (obj.type === 'Identifier') {
const { node } = j(obj).get()
// Get the definition of the variable
const identifier: j.ASTPath<j.VariableDeclarator> = program
.find(j.VariableDeclarator, {
id: {name: node.name},
id: { name: node.name },
})
.get()
// Return what is after the `=`
return identifier.value.init ? recursiveConfigSearch(program, identifier.value.init) : undefined
} else if (obj.type === "CallExpression") {
return identifier.value.init
? recursiveConfigSearch(program, identifier.value.init)
: undefined
} else if (obj.type === 'CallExpression') {
// If it's an function call (like `withBundleAnalyzer`), get the first argument
if (obj.arguments.length === 0) {
// If it has no arguments, create an empty object: `{}`
@@ -28,10 +30,10 @@ function recursiveConfigSearch(
return config
} else {
const arg = obj.arguments[0]
if (arg.type === "SpreadElement") return undefined
if (arg.type === 'SpreadElement') return undefined
else return recursiveConfigSearch(program, arg)
}
} else if (obj.type === "ObjectExpression") {
} else if (obj.type === 'ObjectExpression') {
// If it's an object, return it
return obj
} else {
@@ -39,15 +41,17 @@ function recursiveConfigSearch(
}
}
export type TransformBlitzConfigCallback = (config: j.ObjectExpression) => j.ObjectExpression
export type TransformBlitzConfigCallback = (
config: j.ObjectExpression
) => j.ObjectExpression
export function transformBlitzConfig(
program: Program,
transform: TransformBlitzConfigCallback,
transform: TransformBlitzConfigCallback
): Program {
let moduleExportsExpressions = program.find(j.AssignmentExpression, {
operator: "=",
left: {object: {name: "module"}, property: {name: "exports"}},
operator: '=',
left: { object: { name: 'module' }, property: { name: 'exports' } },
right: {},
})
@@ -59,10 +63,10 @@ export function transformBlitzConfig(
let moduleExportExpression = j.expressionStatement(
j.assignmentExpression(
"=",
j.memberExpression(j.identifier("module"), j.identifier("exports")),
config,
),
'=',
j.memberExpression(j.identifier('module'), j.identifier('exports')),
config
)
)
program.get().node.program.body.push(moduleExportExpression)
@@ -71,14 +75,14 @@ export function transformBlitzConfig(
let config: j.ObjectExpression | undefined = recursiveConfigSearch(
program,
moduleExportsExpression.value.right,
moduleExportsExpression.value.right
)
if (config) {
config = transform(config)
} else {
console.warn(
"The configuration couldn't be found, but there is a 'module.exports' inside `blitz.config.js`",
"The configuration couldn't be found, but there is a 'module.exports' inside `blitz.config.js`"
)
}
} else {

View File

@@ -1,17 +1,17 @@
import type {ExpressionKind} from "ast-types/gen/kinds"
import j from "jscodeshift"
import {JsonObject, JsonValue} from "../types"
import {Program} from "../types"
import {findModuleExportsExpressions} from "./find-module-exports-expressions"
import type { ExpressionKind } from 'ast-types/gen/kinds'
import j from 'jscodeshift'
import { JsonObject, JsonValue } from '../types'
import { Program } from '../types'
import { findModuleExportsExpressions } from './find-module-exports-expressions'
type AddBabelItemDefinition = string | [name: string, options: JsonObject]
const jsonValueToExpression = (value: JsonValue): ExpressionKind =>
typeof value === "string"
typeof value === 'string'
? j.stringLiteral(value)
: typeof value === "number"
: typeof value === 'number'
? j.numericLiteral(value)
: typeof value === "boolean"
: typeof value === 'boolean'
? j.booleanLiteral(value)
: value === null
? j.nullLiteral()
@@ -19,16 +19,22 @@ const jsonValueToExpression = (value: JsonValue): ExpressionKind =>
? j.arrayExpression(value.map(jsonValueToExpression))
: j.objectExpression(
Object.entries(value)
.filter((entry): entry is [string, JsonValue] => entry[1] !== undefined)
.filter(
(entry): entry is [string, JsonValue] => entry[1] !== undefined
)
.map(([key, value]) =>
j.objectProperty(j.stringLiteral(key), jsonValueToExpression(value)),
),
j.objectProperty(j.stringLiteral(key), jsonValueToExpression(value))
)
)
function updateBabelConfig(program: Program, item: AddBabelItemDefinition, key: string): Program {
function updateBabelConfig(
program: Program,
item: AddBabelItemDefinition,
key: string
): Program {
findModuleExportsExpressions(program).forEach((moduleExportsExpression) => {
j(moduleExportsExpression)
.find(j.ObjectProperty, {key: {name: key}})
.find(j.ObjectProperty, { key: { name: key } })
.forEach((items) => {
// Don't add it again if it already exists,
// that what this code does. For simplicity,
@@ -36,14 +42,20 @@ function updateBabelConfig(program: Program, item: AddBabelItemDefinition, key:
const itemName = Array.isArray(item) ? item[0] : item
if (items.node.value.type === "Literal" || items.node.value.type === "StringLiteral") {
if (
items.node.value.type === 'Literal' ||
items.node.value.type === 'StringLiteral'
) {
// {
// presets: "this-preset"
// }
if (itemName !== items.node.value.value) {
items.node.value = j.arrayExpression([items.node.value, jsonValueToExpression(item)])
items.node.value = j.arrayExpression([
items.node.value,
jsonValueToExpression(item),
])
}
} else if (items.node.value.type === "ArrayExpression") {
} else if (items.node.value.type === 'ArrayExpression') {
// {
// presets: ["this-preset", "maybe-another", ...]
// }
@@ -52,22 +64,25 @@ function updateBabelConfig(program: Program, item: AddBabelItemDefinition, key:
for (const [i, element] of items.node.value.elements.entries()) {
if (!element) continue
if (element.type === "Literal" || element.type === "StringLiteral") {
if (
element.type === 'Literal' ||
element.type === 'StringLiteral'
) {
// {
// presets: [..., "this-preset", ...]
// }
if (element.value === itemName) return
} else if (element.type === "ArrayExpression") {
} else if (element.type === 'ArrayExpression') {
// {
// presets: [..., ["this-preset"], ...]
// }
if (
(element.elements[0]?.type === "Literal" ||
element.elements[0]?.type === "StringLiteral") &&
(element.elements[0]?.type === 'Literal' ||
element.elements[0]?.type === 'StringLiteral') &&
element.elements[0].value === itemName
) {
if (
element.elements[1]?.type === "ObjectExpression" &&
element.elements[1]?.type === 'ObjectExpression' &&
element.elements[1].properties.length > 0
) {
// The preset has a config.
@@ -81,7 +96,10 @@ function updateBabelConfig(program: Program, item: AddBabelItemDefinition, key:
const value = item[1][key]
if (value === undefined) continue
obj.properties.push(
j.objectProperty(j.stringLiteral(key), jsonValueToExpression(value)),
j.objectProperty(
j.stringLiteral(key),
jsonValueToExpression(value)
)
)
}
@@ -105,7 +123,11 @@ function updateBabelConfig(program: Program, item: AddBabelItemDefinition, key:
return program
}
export const addBabelPreset = (program: Program, preset: AddBabelItemDefinition): Program =>
updateBabelConfig(program, preset, "presets")
export const addBabelPlugin = (program: Program, plugin: AddBabelItemDefinition): Program =>
updateBabelConfig(program, plugin, "plugins")
export const addBabelPreset = (
program: Program,
preset: AddBabelItemDefinition
): Program => updateBabelConfig(program, preset, 'presets')
export const addBabelPlugin = (
program: Program,
plugin: AddBabelItemDefinition
): Program => updateBabelConfig(program, plugin, 'plugins')

View File

@@ -0,0 +1,24 @@
import {
CommentKind,
TypeAnnotationKind,
TSTypeAnnotationKind,
} from 'ast-types/gen/kinds'
import j from 'jscodeshift'
export function withComments<
Node extends {
comments?: CommentKind[] | null
}
>(node: Node, comments: CommentKind[]): Node {
node.comments = comments
return node
}
export function withTypeAnnotation<
Node extends {
typeAnnotation?: TypeAnnotationKind | TSTypeAnnotationKind | null
}
>(node: Node, type: Parameters<typeof j.tsTypeAnnotation>[0]): Node {
node.typeAnnotation = j.tsTypeAnnotation(type)
return node
}

View File

@@ -1,10 +1,13 @@
import j from "jscodeshift"
import {Program} from "../types"
import j from 'jscodeshift'
import { Program } from '../types'
export function wrapBlitzConfig(program: Program, functionName: string): Program {
export function wrapBlitzConfig(
program: Program,
functionName: string
): Program {
let moduleExportsExpressions = program.find(j.AssignmentExpression, {
operator: "=",
left: {object: {name: "module"}, property: {name: "exports"}},
operator: '=',
left: { object: { name: 'module' }, property: { name: 'exports' } },
right: {},
})
@@ -12,19 +15,20 @@ export function wrapBlitzConfig(program: Program, functionName: string): Program
if (moduleExportsExpressions.length === 0) {
let moduleExportExpression = j.expressionStatement(
j.assignmentExpression(
"=",
j.memberExpression(j.identifier("module"), j.identifier("exports")),
j.callExpression(j.identifier(functionName), [j.objectExpression([])]),
),
'=',
j.memberExpression(j.identifier('module'), j.identifier('exports')),
j.callExpression(j.identifier(functionName), [j.objectExpression([])])
)
)
program.get().node.program.body.push(moduleExportExpression)
} else if (moduleExportsExpressions.length === 1) {
let moduleExportsExpression: j.ASTPath<j.AssignmentExpression> = moduleExportsExpressions.get()
moduleExportsExpression.value.right = j.callExpression(j.identifier(functionName), [
moduleExportsExpression.value.right,
])
moduleExportsExpression.value.right = j.callExpression(
j.identifier(functionName),
[moduleExportsExpression.value.right]
)
} else {
console.warn("There are multiple 'module.exports' inside 'blitz.config.js'")
}

View File

@@ -1,4 +1,4 @@
import type * as j from "jscodeshift"
import type * as j from 'jscodeshift'
export interface RecipeMeta {
name: string
@@ -7,7 +7,7 @@ export interface RecipeMeta {
repoLink: string
}
export type RecipeCLIArgs = {[Key in string]?: string | true}
export type RecipeCLIArgs = { [Key in string]?: string | true }
export interface RecipeCLIFlags {
yesToAll: boolean
@@ -20,7 +20,7 @@ Matches a JSON object.
This type can be useful to enforce some input to be JSON-compatible or as a super-type to be extended from. Don't use this as a direct return type as the user would have to double-cast it: `jsonObject as unknown as CustomResponse`. Instead, you could extend your CustomResponse type from it to ensure your type only uses JSON-compatible types: `interface CustomResponse extends JsonObject { … }`.
@see https://github.com/sindresorhus/type-fest
*/
export type JsonObject = {[Key in string]?: JsonValue}
export type JsonObject = { [Key in string]?: JsonValue }
/**
Matches a JSON array.

View File

@@ -1,8 +1,12 @@
import * as fs from "fs-extra"
import * as path from "path"
import * as fs from 'fs-extra'
import * as path from 'path'
function ext(jsx = false) {
return fs.existsSync(path.resolve("tsconfig.json")) ? (jsx ? ".tsx" : ".ts") : ".js"
return fs.existsSync(path.resolve('tsconfig.json'))
? jsx
? '.tsx'
: '.ts'
: '.js'
}
export const paths = {
@@ -16,15 +20,15 @@ export const paths = {
return `app/pages/index${ext(true)}`
},
babelConfig() {
return "babel.config.js"
return 'babel.config.js'
},
blitzConfig() {
return `blitz.config${ext()}`
},
packageJson() {
return "package.json"
return 'package.json'
},
prismaSchema() {
return "db/schema.prisma"
return 'db/schema.prisma'
},
}

View File

@@ -1,21 +1,21 @@
import * as fs from "fs-extra"
import j from "jscodeshift"
import getBabelOptions, {Overrides} from "recast/parsers/_babel_options"
import * as babel from "recast/parsers/babel"
import {Program} from "../types"
import * as fs from 'fs-extra'
import j from 'jscodeshift'
import getBabelOptions, { Overrides } from 'recast/parsers/_babel_options'
import * as babel from 'recast/parsers/babel'
import { Program } from '../types'
export const customTsParser = {
parse(source: string, options?: Overrides) {
const babelOptions = getBabelOptions(options)
babelOptions.plugins.push("typescript")
babelOptions.plugins.push("jsx")
babelOptions.plugins.push('typescript')
babelOptions.plugins.push('jsx')
return babel.parser.parse(source, babelOptions)
},
}
export enum TransformStatus {
Success = "success",
Failure = "failure",
Success = 'success',
Failure = 'failure',
}
export interface TransformResult {
status: TransformStatus
@@ -28,19 +28,22 @@ export type Transformer = (program: Program) => Program | Promise<Program>
export function stringProcessFile(
original: string,
transformerFn: StringTransformer,
transformerFn: StringTransformer
): string | Promise<string> {
return transformerFn(original)
}
export async function processFile(original: string, transformerFn: Transformer): Promise<string> {
const program = j(original, {parser: customTsParser})
export async function processFile(
original: string,
transformerFn: Transformer
): Promise<string> {
const program = j(original, { parser: customTsParser })
return (await transformerFn(program)).toSource()
}
export async function transform(
processFile: (original: string) => Promise<string>,
targetFilePaths: string[],
targetFilePaths: string[]
): Promise<TransformResult[]> {
const results: TransformResult[] = []
for (const filePath of targetFilePaths) {
@@ -53,7 +56,7 @@ export async function transform(
}
try {
const fileBuffer = fs.readFileSync(filePath)
const fileSource = fileBuffer.toString("utf-8")
const fileSource = fileBuffer.toString('utf-8')
const transformedCode = await processFile(fileSource)
fs.writeFileSync(filePath, transformedCode)
results.push({

View File

@@ -0,0 +1,12 @@
import { useInput } from 'ink'
export function useEnterToContinue(
cb: Function,
additionalCondition: boolean = true
) {
useInput((_input, key) => {
if (additionalCondition && key.return) {
cb()
}
})
}

View File

@@ -0,0 +1,7 @@
import { useStdin } from 'ink'
import { RecipeCLIFlags } from '../types'
export function useUserInput(cliFlags: RecipeCLIFlags) {
const { isRawModeSupported } = useStdin()
return isRawModeSupported && !cliFlags.yesToAll
}

View File

@@ -0,0 +1,91 @@
import { spawn } from 'cross-spawn'
import { existsSync } from 'fs-extra'
import { mocked } from 'ts-jest/utils'
import * as AddDependencyExecutor from '../../src/executors/add-dependency-executor'
jest.mock('fs-extra')
jest.mock('cross-spawn')
describe('add dependency executor', () => {
const testConfiguration = {
stepId: 'addDependencies',
stepName: 'Add dependencies',
stepType: 'add-dependency',
explanation: 'This step will add some dependencies for testing purposes',
packages: [{ name: 'typescript', version: '4' }, { name: 'ts-node' }],
}
it('should properly identify executor', () => {
const wrongConfiguration = {
stepId: 'wrongStep',
stepName: 'Wrong Step',
stepType: 'wrong-type',
explanation: 'This step is wrong',
}
expect(
AddDependencyExecutor.isAddDependencyExecutor(wrongConfiguration)
).toBeFalsy()
expect(
AddDependencyExecutor.isAddDependencyExecutor(testConfiguration)
).toBeTruthy()
})
it('should choose proper package manager according to lock file', () => {
mocked(existsSync).mockReturnValueOnce(true)
expect(AddDependencyExecutor.getPackageManager()).toEqual('yarn')
expect(AddDependencyExecutor.getPackageManager()).toEqual('npm')
})
it('should issue proper commands according to the specified packages', async () => {
const mockedSpawn = mockSpawn()
mocked(spawn).mockImplementation(mockedSpawn.spawn as any)
// NPM
mocked(existsSync).mockReturnValue(false)
await AddDependencyExecutor.installPackages(
testConfiguration.packages,
true
)
await AddDependencyExecutor.installPackages(
testConfiguration.packages,
false
)
// Yarn
mocked(existsSync).mockReturnValue(true)
await AddDependencyExecutor.installPackages(
testConfiguration.packages,
true
)
await AddDependencyExecutor.installPackages(
testConfiguration.packages,
false
)
expect(mockedSpawn.calls.length).toEqual(4)
expect(mockedSpawn.calls[0]).toEqual(
'npm install --save-dev typescript@4 ts-node'
)
expect(mockedSpawn.calls[1]).toEqual('npm install typescript@4 ts-node')
expect(mockedSpawn.calls[2]).toEqual('yarn add -D typescript@4 ts-node')
expect(mockedSpawn.calls[3]).toEqual('yarn add typescript@4 ts-node')
})
})
/**
* Primitive mock of spawn function
*/
const mockSpawn = () => {
let calls: string[] = []
return {
spawn: (command: string, args: string[], _: unknown = {}) => {
calls.push(`${command} ${args.join(' ')}`)
return {
on: (_: string, resolve: () => void) => resolve(),
}
},
calls,
}
}

View File

@@ -0,0 +1,25 @@
import { render } from 'ink-testing-library'
import React from 'react'
import stripAnsi from 'strip-ansi'
import { Frontmatter } from '../../src/executors/executor'
describe('Executor', () => {
const executorConfig = {
stepId: 'newFile',
stepName: 'New File',
stepType: 'new-file',
explanation: 'Testing text for a new file',
}
it('should render Frontmatter', () => {
const { lastFrame } = render(<Frontmatter executor={executorConfig} />)
expect(stripAnsi(lastFrame())).toMatchSnapshot()
})
it('should contain a step name and explanation', () => {
const { frames } = render(<Frontmatter executor={executorConfig} />)
expect(frames[0].includes('New File')).toBeTruthy()
expect(frames[0].includes('Testing text for a new file')).toBeTruthy()
})
})

View File

@@ -0,0 +1,39 @@
import { render } from 'ink-testing-library'
import React from 'react'
import stripAnsi from 'strip-ansi'
import { Commit as PrintMessageExecutor } from '../../src/executors/print-message-executor'
describe('Executor', () => {
const executorConfig = {
stepId: 'printMessage',
stepName: 'Print message',
stepType: 'print-message',
explanation: 'Testing text for a print message',
message: 'My message',
}
it('should render PrintMessageExecutor', () => {
const { lastFrame } = render(
<PrintMessageExecutor
cliArgs={null}
cliFlags={{ yesToAll: false }}
onChangeCommitted={() => {}}
step={executorConfig}
/>
)
expect(stripAnsi(lastFrame())).toMatchSnapshot()
})
it('should contain a step name and explanation', () => {
const { frames } = render(
<PrintMessageExecutor
cliArgs={null}
cliFlags={{ yesToAll: false }}
onChangeCommitted={() => {}}
step={executorConfig}
/>
)
expect(frames[0].includes('My message')).toBeTruthy()
})
})

View File

@@ -27,6 +27,9 @@ module.exports = withBundleAnalyzer({
cli: {
clearConsoleOnBlitzDev: true
},
codegen: {
templateDir: \\"my-templates\\",
},
log: {
// level: \\"trace\\",
},

View File

@@ -0,0 +1,36 @@
import { addImport, customTsParser } from '@blitzjs/installer'
import j from 'jscodeshift'
function executeImport(
fileStr: string,
importStatement: j.ImportDeclaration
): string {
return addImport(
j(fileStr, { parser: customTsParser }),
importStatement
).toSource({ tabWidth: 60 })
}
describe('addImport transform', () => {
it('adds import at start of file with no imports present', () => {
const file = `export const truth = () => 42`
const importStatement = j.importDeclaration(
[j.importDefaultSpecifier(j.identifier('React'))],
j.literal('react')
)
expect(executeImport(file, importStatement)).toMatchSnapshot()
})
it('adds import at the end of all imports if imports are present', () => {
const file = `import React from 'react'
export default function Comp() {
return <div>hello world!</div>
}`
const importStatement = j.importDeclaration(
[],
j.literal('app/styles/app.css')
)
expect(executeImport(file, importStatement)).toMatchSnapshot()
})
})

Some files were not shown because too many files have changed in this diff Show More