1
0
mirror of synced 2026-02-09 00:00:11 -05:00

Compare commits

..

16 Commits

Author SHA1 Message Date
JuanM04
4299bb6c1a Updated react types 2021-12-28 23:05:54 -03:00
JuanM04
0e46ff35f4 Merge branch 'canary' into react-18-rc 2021-12-25 13:03:18 -03:00
JuanM04
de26e44b1b Updated some tests 2021-12-14 15:28:35 -03:00
JuanM04
1ed39d1dc3 hydrateRoot 2021-12-14 15:28:22 -03:00
JuanM04
254e923922 Merge branch 'canary' into react-18-rc 2021-12-14 12:22:20 -03:00
JuanM04
2b4412e28d "concurrent mode" doesn't exist anymore 2021-12-14 12:21:36 -03:00
JuanM04
1627db14da Merge branch 'canary' into react-18-rc 2021-12-10 21:12:53 -03:00
JuanM04
e2a0a36f26 Merge branch 'canary' into react-18-rc 2021-12-09 16:41:40 -03:00
JuanM04
06ae0dbe44 Remove 'data-reactroot' 2021-12-09 15:21:20 -03:00
JuanM04
dd7fd57715 Upgraded testing library 2021-12-09 15:17:47 -03:00
JuanM04
3ce42ae2ba Remove local volta 2021-12-09 14:12:17 -03:00
JuanM04
c9727a2487 Added react to installer 2021-12-09 14:06:09 -03:00
JuanM04
0d30fc7b0e Upgraded nextjs 2021-12-09 14:06:02 -03:00
JuanM04
117d76f8f5 Upgraded templates 2021-12-09 14:05:53 -03:00
JuanM04
bf47b609b9 Upgraded examples + added @types/react-dom 2021-12-09 14:05:41 -03:00
JuanM04
decd93406f Upgraded to React 18 RC 2021-12-09 14:05:07 -03:00
103 changed files with 644 additions and 1540 deletions

View File

@@ -3590,69 +3590,6 @@
"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"
]
}
],
"contributorsPerLine": 7,

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-388-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-381-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">
@@ -109,6 +109,12 @@ Your financial contributions help ensure Blitz continues to be developed and mai
<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"/>
@@ -228,14 +234,6 @@ _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>
</tr>
</table>
<!-- markdownlint-enable -->
@@ -742,15 +740,6 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
<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>
</tr>
</table>

24
assets/digsas.svg Normal file
View File

@@ -0,0 +1,24 @@
<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>

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
assets/usertrack.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -16,6 +16,9 @@ module.exports = withBundleAnalyzer({
cli: {
clearConsoleOnBlitzDev: false,
},
codegen: {
templateDir: "./my-templates",
},
log: {
// level: "trace",
},
@@ -37,69 +40,4 @@ module.exports = withBundleAnalyzer({
return config
},
*/
codegen: {
templateDir: "./my-templates",
fieldTypeMap: {
string: {
component: "LabeledTextField",
inputType: "text",
zodType: "string",
prismaType: "String",
},
boolean: {
component: "LabeledTextField",
inputType: "text",
zodType: "boolean",
prismaType: "Boolean",
},
int: {
component: "LabeledTextField",
inputType: "number",
zodType: "number",
prismaType: "Int",
},
number: {
component: "LabeledTextField",
inputType: "number",
zodType: "number",
prismaType: "Int",
},
bigint: {
component: "LabeledTextField",
inputType: "number",
zodType: "number",
prismaType: "BigInt",
},
float: {
component: "LabeledTextField",
inputType: "number",
zodType: "number",
prismaType: "Float",
},
decimal: {
component: "LabeledTextField",
inputType: "number",
zodType: "number",
prismaType: "Decimal",
},
datetime: {
component: "LabeledTextField",
inputType: "string",
zodType: "string",
prismaType: "DateTime",
},
uuid: {
component: "LabeledTextField",
inputType: "text",
zodType: "string().uuid",
prismaType: "Uuid",
},
json: {
component: "LabeledTextField",
inputType: "text",
zodType: "any",
prismaType: "Json",
},
},
},
})

View File

@@ -30,26 +30,27 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.45.2",
"blitz": "0.45.0-canary.0",
"final-form": "4.20.1",
"passport-auth0": "1.4.0",
"passport-github2": "0.1.12",
"passport-twitter": "1.0.4",
"prisma": "2.24.1",
"react": "0.0.0-experimental-6a589ad71",
"react-dom": "0.0.0-experimental-6a589ad71",
"react": "18.0.0-rc.0",
"react-dom": "18.0.0-rc.0",
"react-final-form": "6.5.2"
},
"devDependencies": {
"@cypress/skip-test": "2.6.0",
"@next/bundle-analyzer": "^10.0.6",
"@testing-library/react": "11.2.5",
"@testing-library/react": "13.0.0-alpha.5",
"@testing-library/react-hooks": "^4.0.1",
"@types/passport-auth0": "1.0.4",
"@types/passport-github2": "1.2.4",
"@types/passport-twitter": "1.0.36",
"@types/preview-email": "2.0.0",
"@types/react": "17.0.2",
"@types/react": "17.0.37",
"@types/react-dom": "17.0.11",
"cross-env": "7.0.3",
"cypress": "6.2.1",
"eslint": "7.21.0",

View File

@@ -31,19 +31,20 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.45.2",
"blitz": "0.45.0-canary.0",
"final-form": "4.20.1",
"prisma": "2.24.1",
"react": "0.0.0-experimental-6a589ad71",
"react-dom": "0.0.0-experimental-6a589ad71",
"react": "18.0.0-rc.0",
"react-dom": "18.0.0-rc.0",
"react-final-form": "6.5.2",
"secure-password": "4.0.0"
},
"devDependencies": {
"@cypress/skip-test": "2.6.0",
"@testing-library/react": "11.2.5",
"@testing-library/react": "13.0.0-alpha.5",
"@testing-library/react-hooks": "^4.0.1",
"@types/react": "17.0.2",
"@types/react": "17.0.37",
"@types/react-dom": "17.0.11",
"@types/secure-password": "3.1.0",
"cypress": "6.2.1",
"eslint": "7.21.0",

View File

@@ -34,17 +34,18 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.45.2",
"blitz": "0.45.0-canary.0",
"final-form": "4.20.1",
"react": "0.0.0-experimental-6a589ad71",
"react-dom": "0.0.0-experimental-6a589ad71",
"react": "18.0.0-rc.0",
"react-dom": "18.0.0-rc.0",
"react-final-form": "6.5.2",
"zod": "3.10.1"
},
"devDependencies": {
"@testing-library/cypress": "8.0.1",
"@types/preview-email": "2.0.0",
"@types/react": "17.0.2",
"@types/react": "17.0.37",
"@types/react-dom": "17.0.11",
"@types/testing-library__cypress": "5.0.9",
"chance": "1.1.8",
"cross-env": "7.0.3",

View File

@@ -28,18 +28,19 @@
]
},
"dependencies": {
"blitz": "0.45.2",
"blitz": "0.45.0-canary.0",
"final-form": "4.20.1",
"graphql": "15.5.0",
"graphql-request": "3.4.0",
"react": "0.0.0-experimental-6a589ad71",
"react-dom": "0.0.0-experimental-6a589ad71",
"react": "18.0.0-rc.0",
"react-dom": "18.0.0-rc.0",
"react-final-form": "6.5.2"
},
"devDependencies": {
"@testing-library/react": "11.2.5",
"@testing-library/react": "13.0.0-alpha.5",
"@testing-library/react-hooks": "^4.0.1",
"@types/react": "17.0.2",
"@types/react": "17.0.37",
"@types/react-dom": "17.0.11",
"@types/secure-password": "3.1.0",
"eslint": "7.21.0",
"eslint-config-react-app": "~6.0.0",

View File

@@ -26,17 +26,18 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.45.2",
"blitz": "0.45.0-canary.0",
"final-form": "4.20.1",
"next-rosetta": "1.3.1",
"react": "0.0.0-experimental-6a589ad71",
"react-dom": "0.0.0-experimental-6a589ad71",
"react": "18.0.0-rc.0",
"react-dom": "18.0.0-rc.0",
"react-final-form": "6.5.2",
"zod": "3.10.1"
},
"devDependencies": {
"@types/preview-email": "2.0.0",
"@types/react": "17.0.2",
"@types/react": "17.0.37",
"@types/react-dom": "17.0.11",
"eslint": "7.21.0",
"husky": "5.1.2",
"lint-staged": "10.5.4",

View File

@@ -26,14 +26,15 @@
]
},
"dependencies": {
"blitz": "0.45.2",
"blitz": "0.45.0-canary.0",
"knex": "0.21.16",
"react": "0.0.0-experimental-6a589ad71",
"react-dom": "0.0.0-experimental-6a589ad71",
"react": "18.0.0-rc.0",
"react-dom": "18.0.0-rc.0",
"sqlite3": "5.0.2"
},
"devDependencies": {
"@types/react": "17.0.2",
"@types/react": "17.0.37",
"@types/react-dom": "17.0.11",
"eslint": "7.21.0",
"eslint-config-react-app": "~6.0.0",
"eslint-plugin-flowtype": "~5.2.0",

View File

@@ -33,10 +33,10 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.45.2",
"blitz": "0.45.0-canary.0",
"prisma": "2.24.1",
"react": "0.0.0-experimental-6a589ad71",
"react-dom": "0.0.0-experimental-6a589ad71"
"react": "18.0.0-rc.0",
"react-dom": "18.0.0-rc.0"
},
"devDependencies": {
"eslint": "7.21.0",

View File

@@ -33,16 +33,17 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.45.2",
"blitz": "0.45.0-canary.0",
"final-form": "4.20.1",
"prisma": "2.24.1",
"react": "0.0.0-experimental-6a589ad71",
"react-dom": "0.0.0-experimental-6a589ad71",
"react": "18.0.0-rc.0",
"react-dom": "18.0.0-rc.0",
"react-final-form": "6.5.2"
},
"devDependencies": {
"@types/preview-email": "2.0.0",
"@types/react": "17.0.2",
"@types/react": "17.0.37",
"@types/react-dom": "17.0.11",
"eslint": "7.21.0",
"husky": "5.1.2",
"lint-staged": "10.5.4",

View File

@@ -21,15 +21,16 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.45.2",
"blitz": "0.45.0-canary.0",
"final-form": "4.20.1",
"prisma": "2.24.1",
"react": "0.0.0-experimental-6a589ad71",
"react-dom": "0.0.0-experimental-6a589ad71",
"react": "18.0.0-rc.0",
"react-dom": "18.0.0-rc.0",
"react-final-form": "6.5.2"
},
"devDependencies": {
"@types/react": "17.0.2",
"@types/react": "17.0.37",
"@types/react-dom": "17.0.11",
"cypress": "6.2.1",
"start-server-and-test": "1.11.7"
}

View File

@@ -1,5 +1,5 @@
{
"version": "0.45.2",
"version": "0.45.0-canary.0",
"packages": ["packages/*"],
"npmClient": "yarn",
"useWorkspaces": true,

View File

@@ -51,7 +51,7 @@
"@mdx-js/loader": "0.18.0",
"@svgr/webpack": "5.5.0",
"@swc/core": "1.2.74",
"@testing-library/react": "11.2.5",
"@testing-library/react": "13.0.0-alpha.5",
"@types/b64-lite": "1.3.0",
"@types/cheerio": "0.22.16",
"@types/cookie-session": "2.0.42",
@@ -126,10 +126,8 @@
"prettier": "2.2.1",
"pretty-bytes": "5.3.0",
"pretty-ms": "7.0.0",
"react": "0.0.0-experimental-6a589ad71",
"react-18": "npm:react@next",
"react-dom": "0.0.0-experimental-6a589ad71",
"react-dom-18": "npm:react-dom@next",
"react": "18.0.0-rc.0",
"react-dom": "18.0.0-rc.0",
"react-ssr-prepass": "1.0.8",
"release": "6.3.0",
"request-promise-core": "1.1.2",
@@ -158,5 +156,8 @@
},
"engines": {
"node": ">=12.0.0"
},
"volta": {
"extends": "../package.json"
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "eslint-config-blitz",
"version": "0.45.2",
"version": "0.45.0-canary.0",
"description": "Blitz.js eslint config",
"main": "index.js",
"license": "MIT",

View File

@@ -1,6 +1,6 @@
{
"name": "@blitzjs/installer",
"version": "0.45.2",
"version": "0.45.0-canary.0",
"description": "Package installation for the Blitz CLI",
"homepage": "https://github.com/blitz-js/blitz#readme",
"license": "MIT",
@@ -30,10 +30,11 @@
"dependencies": {
"@babel/core": "7.12.10",
"@babel/plugin-transform-typescript": "7.12.1",
"@blitzjs/generator": "0.45.2",
"@blitzjs/generator": "0.45.0-canary.0",
"@mrleebo/prisma-ast": "0.2.6",
"@prisma/sdk": "2.19.0",
"@types/jscodeshift": "0.11.2",
"@types/react": "17.0.37",
"ast-types": "0.14.2",
"cross-spawn": "7.0.3",
"diff": "5.0.0",
@@ -44,6 +45,7 @@
"ink-spinner": "4.0.3",
"ink-testing-library": "2.1.0",
"jscodeshift": "0.13.0",
"react": "18.0.0-rc.0",
"recast": "0.20.5"
},
"gitHead": "d3b9fce0bdd251c2b1890793b0aa1cd77c1c0922"

View File

@@ -1,161 +0,0 @@
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

@@ -2,7 +2,6 @@ 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'
@@ -23,10 +22,6 @@ export interface IRecipeBuilder {
addTransformFilesStep(
step: Omit<TransformFileExecutor.Config, 'stepType'>
): IRecipeBuilder
addRunCommandStep(
step: Omit<RunCommandExecutor.Config, 'stepType'>
): IRecipeBuilder
build(): RecipeExecutor<any>
}
@@ -83,13 +78,6 @@ export function RecipeBuilder(): IRecipeBuilder {
})
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

@@ -7,7 +7,6 @@ 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'
@@ -33,7 +32,6 @@ const ExecutorMap: { [key: string]: Executor } = {
[NewFileExecutor.type]: NewFileExecutor,
[PrintMessageExecutor.type]: PrintMessageExecutor,
[FileTransformExecutor.type]: FileTransformExecutor,
[RunCommandExecutor.type]: RunCommandExecutor,
} as const
interface State {

View File

@@ -1,6 +1,6 @@
{
"name": "@blitzjs/env",
"version": "0.45.2",
"version": "0.45.0-canary.0",
"keywords": [
"react",
"next",

View File

@@ -50,7 +50,6 @@ const specialImports: Record<string, string> = {
getAntiCSRFToken: 'next/data-client',
useSession: 'next/data-client',
useAuthenticatedSession: 'next/data-client',
useRedirectAuthenticated: 'next/data-client',
useAuthorize: 'next/data-client',
useQuery: 'next/data-client',
usePaginatedQuery: 'next/data-client',

View File

@@ -3,7 +3,6 @@ import chalk from 'chalk'
import crypto from 'crypto'
import { readFileSync } from 'fs'
import { codeFrameColumns } from 'next/dist/compiled/babel/code-frame'
import semver from 'next/dist/compiled/semver'
import { isWebpack5, webpack } from 'next/dist/compiled/webpack/webpack'
import path, { join as pathJoin, relative as relativePath } from 'path'
import {
@@ -13,7 +12,6 @@ import {
PAGES_DIR_ALIAS,
} from '../lib/constants'
import { fileExists } from '../lib/file-exists'
import { getPackageVersion } from '../lib/get-package-version'
import { CustomRoutes } from '../lib/load-custom-routes.js'
import { getTypeScriptConfiguration } from '../lib/typescript/getTypeScriptConfiguration'
import {
@@ -246,22 +244,9 @@ export default async function getBaseWebpackConfig(
rewrites.afterFiles.length > 0 ||
rewrites.fallback.length > 0
const hasReactRefresh: boolean = dev && !isServer
const reactDomVersion = await getPackageVersion({
cwd: dir,
name: 'react-dom',
})
const hasReactExperimental: boolean =
Boolean(reactDomVersion) && reactDomVersion!.includes('experimental') // blitz
const hasReact18: boolean =
(Boolean(reactDomVersion) &&
(semver.gte(reactDomVersion!, '18.0.0') ||
semver.coerce(reactDomVersion)?.version === '18.0.0')) ||
hasReactExperimental // blitz
const hasReactRoot: boolean = config.experimental.reactRoot ?? hasReact18
// Have to set this suspense env for the actual build, because the webpack
// string replace below only affects the build output, not anything during
// the build like static page optimization
process.env.__BLITZ_SUSPENSE_ENABLED = String(hasReactRoot)
const defaultSuspense = config.reactQueryDefaultBehavior === 'suspense'
process.env.__BLITZ_DEFAULT_SUSPENSE = String(defaultSuspense)
const babelConfigFile = await [
'.babelrc',
@@ -1191,7 +1176,7 @@ export default async function getBaseWebpackConfig(
'process.env.__NEXT_DIST_DIR': JSON.stringify(distDir),
}
: {}),
'process.env.__BLITZ_SUSPENSE_ENABLED': JSON.stringify(hasReactRoot),
'process.env.__BLITZ_DEFAULT_SUSPENSE': JSON.stringify(defaultSuspense),
'process.env.__NEXT_TRAILING_SLASH': JSON.stringify(
config.trailingSlash
),
@@ -1204,7 +1189,6 @@ export default async function getBaseWebpackConfig(
'process.env.__NEXT_STRICT_MODE': JSON.stringify(
config.reactStrictMode
),
'process.env.__NEXT_REACT_ROOT': JSON.stringify(hasReactRoot),
'process.env.__NEXT_OPTIMIZE_FONTS': JSON.stringify(
config.optimizeFonts && !dev
),
@@ -1447,7 +1431,6 @@ export default async function getBaseWebpackConfig(
productionBrowserSourceMaps: !!config.productionBrowserSourceMaps,
plugins: config.experimental.plugins,
reactStrictMode: config.reactStrictMode,
reactMode: config.experimental.reactMode,
optimizeFonts: config.optimizeFonts,
optimizeImages: config.experimental.optimizeImages,
optimizeCss: config.experimental.optimizeCss,

View File

@@ -549,7 +549,7 @@ export function renderError(renderErrorProps: RenderErrorProps): Promise<any> {
})
}
let reactRoot: any = null
let reactRoot: ReactDOM.Root | null = null
// On initial render a hydrate should always happen
let shouldHydrate: boolean = true
@@ -563,29 +563,17 @@ function renderReactElement(
}
const reactEl = fn(shouldHydrate ? markHydrateComplete : markRenderComplete)
if (process.env.__NEXT_REACT_ROOT) {
// start blitz
if (!reactRoot) {
const createRootName =
typeof (ReactDOM as any).unstable_createRoot === 'function'
? 'unstable_createRoot'
: 'createRoot'
reactRoot = (ReactDOM as any)[createRootName](domEl, {
hydrate: shouldHydrate,
})
}
reactRoot.render(reactEl)
shouldHydrate = false
// end blitz
} else {
// The check for `.hydrate` is there to support React alternatives like preact
// start blitz
if (!reactRoot) {
if (shouldHydrate) {
ReactDOM.hydrate(reactEl, domEl)
shouldHydrate = false
reactRoot = ReactDOM.hydrateRoot(domEl, reactEl)
} else {
ReactDOM.render(reactEl, domEl)
reactRoot = ReactDOM.createRoot(domEl)
}
}
reactRoot.render(reactEl)
shouldHydrate = false
// end blitz
}
function markHydrateComplete(): void {

View File

@@ -130,7 +130,7 @@ interface UseSessionOptions {
export const useSession = (options: UseSessionOptions = {}): ClientSession => {
const suspense =
options?.suspense ?? Boolean(process.env.__BLITZ_SUSPENSE_ENABLED)
options?.suspense ?? Boolean(process.env.__BLITZ_DEFAULT_SUSPENSE)
let initialState: ClientSession
if (options.initialPublicData) {

View File

@@ -13,7 +13,7 @@ type MutateOptions = {
export const initializeQueryClient = () => {
let suspenseEnabled = true
if (!process.env.CLI_COMMAND_CONSOLE && !process.env.CLI_COMMAND_DB) {
suspenseEnabled = Boolean(process.env.__BLITZ_SUSPENSE_ENABLED)
suspenseEnabled = Boolean(process.env.__BLITZ_DEFAULT_SUSPENSE)
}
return new QueryClient({

View File

@@ -77,7 +77,7 @@ export function useQuery<
)
}
const suspenseEnabled = Boolean(process.env.__BLITZ_SUSPENSE_ENABLED)
const suspenseEnabled = Boolean(process.env.__BLITZ_DEFAULT_SUSPENSE)
let enabled =
isServer && suspenseEnabled
? false
@@ -167,7 +167,7 @@ export function usePaginatedQuery<
)
}
const suspenseEnabled = Boolean(process.env.__BLITZ_SUSPENSE_ENABLED)
const suspenseEnabled = Boolean(process.env.__BLITZ_DEFAULT_SUSPENSE)
let enabled =
isServer && suspenseEnabled
? false
@@ -266,7 +266,7 @@ export function useInfiniteQuery<
)
}
const suspenseEnabled = Boolean(process.env.__BLITZ_SUSPENSE_ENABLED)
const suspenseEnabled = Boolean(process.env.__BLITZ_DEFAULT_SUSPENSE)
let enabled =
isServer && suspenseEnabled
? false

View File

@@ -1,6 +1,6 @@
{
"name": "next",
"version": "0.45.2",
"version": "0.45.0-canary.0",
"nextjsVersion": "11.1.0",
"description": "The React Framework",
"main": "./dist/server/next.js",
@@ -73,7 +73,7 @@
"dependencies": {
"@babel/helper-module-imports": "^7.0.0",
"@babel/runtime": "7.12.5",
"@blitzjs/env": "0.45.2",
"@blitzjs/env": "0.45.0-canary.0",
"@hapi/accept": "5.0.2",
"@next/polyfill-module": "11.1.0",
"@next/react-dev-overlay": "11.1.0",
@@ -200,8 +200,8 @@
"@types/lru-cache": "5.1.0",
"@types/node-fetch": "2.5.8",
"@types/path-to-regexp": "1.7.0",
"@types/react": "17.0.2",
"@types/react-dom": "16.9.4",
"@types/react": "17.0.37",
"@types/react-dom": "17.0.11",
"@types/react-is": "16.7.1",
"@types/semver": "7.3.1",
"@types/send": "0.14.4",

View File

@@ -71,20 +71,6 @@ export interface ESLintConfig {
ignoreDuringBuilds?: boolean
}
export type CodegenField = {
component: string
inputType: string
zodType: string
prismaType: string
default?: string
[index: string]: string | undefined
}
export type CodegenConfig = {
templateDir?: string
fieldTypeMap?: Record<string, CodegenField>
}
export type NextConfig = { [key: string]: any } & {
i18n?: I18NConfig | null
@@ -141,7 +127,9 @@ export type NextConfig = { [key: string]: any } & {
httpsProxy?: string
noProxy?: string
}
codegen?: CodegenConfig
codegen?: {
templateDir?: string
}
log?: {
level?: LogLevel
type?: LogType
@@ -150,6 +138,7 @@ export type NextConfig = { [key: string]: any } & {
customServer?: {
hotReload?: boolean
}
reactQueryDefaultBehavior?: 'legacy' | 'suspense'
// -- Blitz end
future?: {
@@ -166,7 +155,6 @@ export type NextConfig = { [key: string]: any } & {
plugins?: boolean
profiling?: boolean
isrFlushToDisk?: boolean
reactMode?: 'legacy' | 'concurrent' | 'blocking'
workerThreads?: boolean
pageEnv?: boolean
optimizeImages?: boolean
@@ -181,7 +169,6 @@ export type NextConfig = { [key: string]: any } & {
skipValidation?: boolean
}
initServer?: () => void // blitz
reactRoot?: boolean
disableOptimizedLoading?: boolean
gzipSize?: boolean
craCompat?: boolean
@@ -237,6 +224,7 @@ export const defaultConfig: NextConfig = {
serverRuntimeConfig: {},
publicRuntimeConfig: {},
reactStrictMode: false,
reactQueryDefaultBehavior: 'suspense',
httpAgentOptions: {
keepAlive: true,
},

View File

@@ -51,16 +51,19 @@ function assignDefaults(userConfig: { [key: string]: any }) {
if (typeof userConfig.experimental?.reactMode !== 'undefined') {
console.warn(
chalk.yellow.bold('Warning: ') +
'The experimental "reactMode" option has been replaced with "reactRoot". Please update your blitz.config.js.'
'The experimental "reactMode" has been removed as "concurrent mode" doesn\'t exist anymore. Please update your blitz.config.js.'
)
if (typeof userConfig.experimental?.reactRoot === 'undefined') {
userConfig.experimental.reactRoot = ['concurrent', 'blocking'].includes(
userConfig.experimental.reactMode
)
}
delete userConfig.experimental.reactMode
}
if (typeof userConfig.experimental?.reactRoot !== 'undefined') {
console.warn(
chalk.yellow.bold('Warning: ') +
'The experimental "reactRoot" has been removed as "concurrent mode" doesn\'t exist anymore. Please update your blitz.config.js.'
)
delete userConfig.experimental.reactRoot
}
const config = Object.keys(userConfig).reduce<{ [key: string]: any }>(
(currentConfig, key) => {
const value = userConfig[key]

View File

@@ -139,6 +139,22 @@ export const secureProxyMiddleware: Middleware = function (
_res: MiddlewareResponse,
next: (error?: Error) => void
) {
req.protocol = 'https'
req.protocol = getProtocol(req)
next()
}
function getProtocol(req: MiddlewareRequest) {
// @ts-ignore
// For some reason there is no encrypted on socket while it is expected
if (req.connection.encrypted) {
return 'https'
}
const forwardedProto =
req.headers &&
((req.headers['forwarded'] as string)?.match(/(?<=proto=).+/g)?.[0] ||
(req.headers['x-forwarded-proto'] as string))
if (forwardedProto) {
return forwardedProto.split(/\s*,\s*/)[0]
}
return 'http'
}

View File

@@ -1,7 +1,7 @@
import SuperJson from 'superjson'
import type { UrlObject } from 'url'
const errorProps = ['name', 'message', 'code', 'statusCode', 'meta', 'url']
const errorProps = ['name', 'message', 'code', 'statusCode', 'meta']
if (process.env.JEST_WORKER_ID === undefined) {
SuperJson.allowErrorProps(...errorProps)
}

View File

@@ -1,8 +1,10 @@
/// <reference types="node" />
/// <reference types="react" />
/// <reference types="react-dom" />
/// <reference types="react/next" />
/// <reference types="react-dom/next" />
/// <reference types="styled-jsx" />
// TODO: Update `react/next` with `react` reference when React 18.0.0 releases
import React from 'react'
import { ParsedUrlQuery } from 'querystring'
import { IncomingMessage, ServerResponse } from 'http'

View File

@@ -257,7 +257,7 @@ export default (context, renderViaHTTP) => {
'Unknown'
)
).toMatch(
'Objects are not valid as a React child (found: /search/). If you meant to render a collection of children, use an array instead.'
'Objects are not valid as a React child (found: [object RegExp]). If you meant to render a collection of children, use an array instead.'
)
aboutPage.restore()

View File

@@ -1,5 +0,0 @@
module.exports = {
experimental: {
reactRoot: false,
},
}

View File

@@ -1,5 +0,0 @@
module.exports = {
experimental: {
reactRoot: false,
},
}

View File

@@ -1,5 +0,0 @@
module.exports = {
experimental: {
reactRoot: false,
},
}

View File

@@ -14,7 +14,7 @@ describe('Link rendering', () => {
)
const html = ReactDOM.renderToString(element)
expect(html).toMatchInlineSnapshot(
`"<a href=\\"/my-path\\" data-reactroot=\\"\\">to another page</a>"`
`"<a href=\\"/my-path\\">to another page</a>"`
)
})
})

View File

@@ -59,11 +59,29 @@ describe('secure proxy middleware', () => {
expect(reqSecure.protocol).toEqual('https')
})
it('should set http protocol if X-Forwarded-Proto is http', () => {
// @ts-ignore
void secureProxyMiddleware(reqHttp, res, () => null)
expect(reqHttp.protocol).toEqual('http')
})
it('should set https protocol if Forwarded is proto=https', () => {
// @ts-ignore
void secureProxyMiddleware(reqForwardSecure, res, () => null)
expect(reqForwardSecure.protocol).toEqual('https')
})
it('should set http protocol if Forwarded is proto=http', () => {
// @ts-ignore
void secureProxyMiddleware(reqForwardHttp, res, () => null)
expect(reqForwardHttp.protocol).toEqual('http')
})
it('should set http protocol if X-Forwarded-Proto and Forwarded are absent', () => {
// @ts-ignore
void secureProxyMiddleware(reqNoHeader, res, () => null)
expect(reqNoHeader.protocol).toEqual('http')
})
})
describe('handleRequestWithMiddleware', () => {

View File

@@ -17,12 +17,12 @@ import {
beforeAll(() => {
queryClient.clear()
process.env.__BLITZ_SESSION_COOKIE_PREFIX = 'blitz-test'
process.env.__BLITZ_SUSPENSE_ENABLED = 'true'
process.env.__BLITZ_DEFAULT_SUSPENSE = 'true'
})
afterAll(() => {
jest.clearAllMocks()
process.env.__BLITZ_SESSION_COOKIE_PREFIX = undefined
process.env.__BLITZ_SUSPENSE_ENABLED = undefined
process.env.__BLITZ_DEFAULT_SUSPENSE = undefined
})
describe('useQuery', () => {

View File

@@ -2896,6 +2896,17 @@
"@types/yargs" "^16.0.0"
chalk "^4.0.0"
"@jest/types@^27.4.2":
version "27.4.2"
resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.4.2.tgz#96536ebd34da6392c2b7c7737d693885b5dd44a5"
integrity sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==
dependencies:
"@types/istanbul-lib-coverage" "^2.0.0"
"@types/istanbul-reports" "^3.0.0"
"@types/node" "*"
"@types/yargs" "^16.0.0"
chalk "^4.0.0"
"@lerna/add@4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@lerna/add/-/add-4.0.0.tgz#c36f57d132502a57b9e7058d1548b7a565ef183f"
@@ -4449,27 +4460,27 @@
dependencies:
chokidar "^1.7.0"
"@testing-library/dom@^7.28.1":
version "7.29.4"
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.29.4.tgz#1647c2b478789621ead7a50614ad81ab5ae5b86c"
integrity sha512-CtrJRiSYEfbtNGtEsd78mk1n1v2TUbeABlNIcOCJdDfkN5/JTOwQEbbQpoSRxGqzcWPgStMvJ4mNolSuBRv1NA==
"@testing-library/dom@^8.5.0":
version "8.11.1"
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.11.1.tgz#03fa2684aa09ade589b460db46b4c7be9fc69753"
integrity sha512-3KQDyx9r0RKYailW2MiYrSSKEfH0GTkI51UGEvJenvcoDoeRYs0PZpi2SXqtnMClQvCqdtTTpOfFETDTVADpAg==
dependencies:
"@babel/code-frame" "^7.10.4"
"@babel/runtime" "^7.12.5"
"@types/aria-query" "^4.2.0"
aria-query "^4.2.2"
aria-query "^5.0.0"
chalk "^4.1.0"
dom-accessibility-api "^0.5.4"
dom-accessibility-api "^0.5.9"
lz-string "^1.4.4"
pretty-format "^26.6.2"
pretty-format "^27.0.2"
"@testing-library/react@11.2.5":
version "11.2.5"
resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-11.2.5.tgz#ae1c36a66c7790ddb6662c416c27863d87818eb9"
integrity sha512-yEx7oIa/UWLe2F2dqK0FtMF9sJWNXD+2PPtp39BvE0Kh9MJ9Kl0HrZAgEuhUJR+Lx8Di6Xz+rKwSdEPY2UV8ZQ==
"@testing-library/react@13.0.0-alpha.5":
version "13.0.0-alpha.5"
resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-13.0.0-alpha.5.tgz#29bfc36b550e2a1025cbebf7254d5a0a46cb58c5"
integrity sha512-QrxKC/7pTE0ze3wLZNaenGJqsLcbAJL71XqU/ryJTL2pqZBjiJHuxZavl2ZQAxnBQkDQF9oh9my3bKPstWfnhA==
dependencies:
"@babel/runtime" "^7.12.5"
"@testing-library/dom" "^7.28.1"
"@testing-library/dom" "^8.5.0"
"@timsuchanek/copy@^1.4.5":
version "1.4.5"
@@ -4979,10 +4990,10 @@
version "1.2.3"
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
"@types/react-dom@16.9.4":
version "16.9.4"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.4.tgz#0b58df09a60961dcb77f62d4f1832427513420df"
integrity sha512-fya9xteU/n90tda0s+FtN5Ym4tbgxpq/hb/Af24dvs6uYnYn+fspaxw5USlw0R8apDNwxsqumdRoCoKitckQqw==
"@types/react-dom@17.0.11":
version "17.0.11"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.11.tgz#e1eadc3c5e86bdb5f7684e00274ae228e7bcc466"
integrity sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q==
dependencies:
"@types/react" "*"
@@ -5000,12 +5011,13 @@
"@types/prop-types" "*"
csstype "^2.2.0"
"@types/react@17.0.2":
version "17.0.2"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.2.tgz#3de24c4efef902dd9795a49c75f760cbe4f7a5a8"
integrity sha512-Xt40xQsrkdvjn1EyWe1Bc0dJLcil/9x2vAuW7ya+PuQip4UYUaXyhzWmAbwRsdMgwOFHpfp7/FFZebDU6Y8VHA==
"@types/react@17.0.37":
version "17.0.37"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.37.tgz#6884d0aa402605935c397ae689deed115caad959"
integrity sha512-2FS1oTqBGcH/s0E+CjrCCR9+JMpsu9b69RTFO+40ua43ZqP5MmQ4iUde/dMjWR909KxZwmOQIFq6AV6NjEG5xg==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
csstype "^3.0.2"
"@types/resolve@1.17.1":
@@ -5038,6 +5050,11 @@
"@types/glob" "*"
"@types/node" "*"
"@types/scheduler@*":
version "0.16.2"
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==
"@types/secure-password@3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@types/secure-password/-/secure-password-3.1.0.tgz#3070abfbfa63c43d0f50e2fbe59dd24dce913968"
@@ -5982,6 +5999,11 @@ aria-query@^4.2.2:
"@babel/runtime" "^7.10.2"
"@babel/runtime-corejs3" "^7.10.2"
aria-query@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.0.0.tgz#210c21aaf469613ee8c9a62c7f86525e058db52c"
integrity sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==
arity-n@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/arity-n/-/arity-n-1.0.4.tgz#d9e76b11733e08569c0847ae7b39b2860b30b745"
@@ -8653,6 +8675,13 @@ debug@^4.3.2:
dependencies:
ms "2.1.2"
debug@^4.3.2:
version "4.3.3"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664"
integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==
dependencies:
ms "2.1.2"
debug@~0.8.1:
version "0.8.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-0.8.1.tgz#20ff4d26f5e422cb68a1bacbbb61039ad8c1c130"
@@ -8914,10 +8943,10 @@ doctrine@^3.0.0:
dependencies:
esutils "^2.0.2"
dom-accessibility-api@^0.5.4:
version "0.5.4"
resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.4.tgz#b06d059cdd4a4ad9a79275f9d414a5c126241166"
integrity sha512-TvrjBckDy2c6v6RLxPv5QXOnU+SmF9nBII5621Ve5fu6Z/BDrENurBEvlC1f44lKEUVqOpK4w9E5Idc5/EgkLQ==
dom-accessibility-api@^0.5.9:
version "0.5.10"
resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.10.tgz#caa6d08f60388d0bb4539dd75fe458a9a1d0014c"
integrity sha512-Xu9mD0UjrJisTmv7lmVSDMagQcU9R5hwAbxsaAE/35XPnPLJobbuREfV/rraiSaEj/UOvgrzQs66zyTWTlyd+g==
dom-serializer@0:
version "0.2.2"
@@ -10865,7 +10894,7 @@ globby@11.0.1:
merge2 "^1.3.0"
slash "^3.0.0"
globby@11.0.2, globby@^11.0.2:
globby@11.0.2:
version "11.0.2"
resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.2.tgz#1af538b766a3b540ebfb58a32b2e2d5897321d83"
integrity sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==
@@ -10877,7 +10906,7 @@ globby@11.0.2, globby@^11.0.2:
merge2 "^1.3.0"
slash "^3.0.0"
globby@^11.0.0, globby@^11.0.4:
globby@^11.0.0, globby@^11.0.1, globby@^11.0.2 globby@^11.0.4:
version "11.0.4"
resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5"
integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==
@@ -10889,18 +10918,6 @@ globby@^11.0.0, globby@^11.0.4:
merge2 "^1.3.0"
slash "^3.0.0"
globby@^11.0.1:
version "11.0.3"
resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.3.tgz#9b1f0cb523e171dd1ad8c7b2a9fb4b644b9593cb"
integrity sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==
dependencies:
array-union "^2.1.0"
dir-glob "^3.0.1"
fast-glob "^3.1.1"
ignore "^5.1.4"
merge2 "^1.3.0"
slash "^3.0.0"
globby@^9.2.0:
version "9.2.0"
resolved "https://registry.yarnpkg.com/globby/-/globby-9.2.0.tgz#fd029a706c703d29bdd170f4b6db3a3f7a7cb63d"
@@ -17046,6 +17063,16 @@ pretty-format@^27.0.0-next.8:
ansi-styles "^5.0.0"
react-is "^17.0.1"
pretty-format@^27.0.2:
version "27.4.2"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.4.2.tgz#e4ce92ad66c3888423d332b40477c87d1dac1fb8"
integrity sha512-p0wNtJ9oLuvgOQDEIZ9zQjZffK7KtyR6Si0jnXULIDwrlNF8Cuir3AZP0hHv0jmKuNN/edOnbMjnzd4uTcmWiw==
dependencies:
"@jest/types" "^27.4.2"
ansi-regex "^5.0.1"
ansi-styles "^5.0.0"
react-is "^17.0.1"
pretty-hrtime@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
@@ -17427,14 +17454,6 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7, rc@^1.2.8:
minimist "^1.2.0"
strip-json-comments "~2.0.1"
"react-18@npm:react@next":
version "18.0.0-alpha-c76e4dbbc-20210722"
resolved "https://registry.yarnpkg.com/react/-/react-18.0.0-alpha-c76e4dbbc-20210722.tgz#a1591fa4926bb1c514552f77efcc4b4744448f2f"
integrity sha512-dtRjRJVHPA25oi29ZFEuLX6R7Rdk5ikCamiDRD0LCB1IpR5hiGKGcNjSxU/rN7rAxs8iRggi15Fg9k1jAK7oBQ==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
react-devtools-core@^4.19.1:
version "4.21.0"
resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-4.21.0.tgz#a54c9a0fd7261491e616d6c87d1869e011d8521d"
@@ -17443,23 +17462,14 @@ react-devtools-core@^4.19.1:
shell-quote "^1.6.1"
ws "^7"
"react-dom-18@npm:react-dom@next":
version "18.0.0-alpha-c76e4dbbc-20210722"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.0.0-alpha-c76e4dbbc-20210722.tgz#4fc4518926332983788d48aaad0c6ca5e5d806e5"
integrity sha512-lV/+kWzfPq8HLdFnDN1UrJ5blXVFRYCrdOJyZyr9YMZODBl63kpPR7gtszSC4lWiPiMw6K8X+4a3UFU96L7pHQ==
react-dom@18.0.0-rc.0:
version "18.0.0-rc.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.0.0-rc.0.tgz#aa07044bdd6399ff94c664b2985e2e25948fbf3e"
integrity sha512-tdD1n0svTndHBQvVAq/f2Kx7FgQ30CpSLp87/neQKAHPW5WtdgW1sBSwmFAcMQOrmstTuP0M+zRlH86f9kMX/A==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
scheduler "0.21.0-alpha-c76e4dbbc-20210722"
react-dom@0.0.0-experimental-6a589ad71:
version "0.0.0-experimental-6a589ad71"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-0.0.0-experimental-6a589ad71.tgz#24ace0c6b0464bdafbc42ebcec783a99aa40d175"
integrity sha512-BMJnyJtnqU/1kzcTS2DHwHZDgy2xKijcFtY48KzuZ+0a2dTW4oe5CWPe5O3D7kfP9hLfyPlUt5aWPNv+myxkmA==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
scheduler "0.0.0-experimental-6a589ad71"
scheduler "^0.21.0-rc.0"
react-is@17.0.2:
version "17.0.2"
@@ -17504,10 +17514,10 @@ react-ssr-prepass@1.0.8:
dependencies:
object-is "^1.0.1"
react@0.0.0-experimental-6a589ad71:
version "0.0.0-experimental-6a589ad71"
resolved "https://registry.yarnpkg.com/react/-/react-0.0.0-experimental-6a589ad71.tgz#31a6e680646f715e318acd502d8fa683e19ed7aa"
integrity sha512-g+cR05rMkxnFsx90a1Nu/Yb0JAJ7gO0CV84D6E3RIJgsglBKIOrRA2yWE+aQeGFvyoPisY3FzR0w1dmjrhn2Sg==
react@18.0.0-rc.0:
version "18.0.0-rc.0"
resolved "https://registry.yarnpkg.com/react/-/react-18.0.0-rc.0.tgz#60bfcf1edd0b35fbeeeca852515c6cc2ce06a6eb"
integrity sha512-PawosMBgF8k5Nlc3++ibzjFqPvo1XKv80MNtVYqz3abHHB2w3IpU65sSdSmBd2ooCwVhcp9b1vkx/twqhakNtA==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
@@ -18551,18 +18561,10 @@ saxes@^5.0.1:
dependencies:
xmlchars "^2.2.0"
scheduler@0.0.0-experimental-6a589ad71:
version "0.0.0-experimental-6a589ad71"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.0.0-experimental-6a589ad71.tgz#7eb02e050b4334704a3e89d699b7f8ee7c43812b"
integrity sha512-68ixKn+3Q6nWUuyMQXpsDaR4HbE+28qPwgOJ85gyj6ZxNuXpQCf7u9bIuDVxPibqssqf9nOICttpCA0iKuTvlA==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
scheduler@0.21.0-alpha-c76e4dbbc-20210722:
version "0.21.0-alpha-c76e4dbbc-20210722"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.21.0-alpha-c76e4dbbc-20210722.tgz#7172827a6ed0829e41d1c07cbbf7d9fea6b018ba"
integrity sha512-X4Xv2zq1OXxsQNR48reXnOQ9kGnS/mY0cCAusJ6Sm/JBUT83+zetG2sPZPFQSS1np2zkmgMa4+f5H/t2U6AW6Q==
scheduler@^0.21.0-rc.0:
version "0.21.0-rc.0-next-f2a59df48-20211208"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.21.0-rc.0-next-f2a59df48-20211208.tgz#54e18e1d360194fd54b47a00616e46403fcabdf1"
integrity sha512-x0oLd3YIih9GHqWTaFYejVe6Au+4TadOWZciAq8m4+Fuo5qCi4/3M35a9irVSIP3+qcg/fCqHKJETT9G0ejD1A==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"

View File

@@ -98,7 +98,7 @@
"@rollup/pluginutils": "4.1.0",
"@size-limit/preset-small-lib": "4.9.2",
"@testing-library/jest-dom": "5.11.9",
"@testing-library/react": "11.2.5",
"@testing-library/react": "13.0.0-alpha.5",
"@testing-library/react-hooks": "^4.0.1",
"@testing-library/user-event": "13.1.9",
"@types/b64-lite": "1.3.0",
@@ -131,8 +131,8 @@
"@types/progress": "^2.0.3",
"@types/pump": "1.1.0",
"@types/pumpify": "1.4.1",
"@types/react": "17.0.2",
"@types/react-dom": "16.9.4",
"@types/react": "17.0.37",
"@types/react-dom": "17.0.11",
"@types/readable-stream": "2.3.9",
"@types/rimraf": "3.0.0",
"@types/tar": "4.0.4",
@@ -184,9 +184,9 @@
"prettier": "2.2.1",
"prettier-plugin-prisma": "0.4.0",
"prompt": "1.1.0",
"react": "0.0.0-experimental-6a589ad71",
"react-dom": "0.0.0-experimental-6a589ad71",
"react-test-renderer": "17.0.1",
"react": "18.0.0-rc.0",
"react-dom": "18.0.0-rc.0",
"react-test-renderer": "18.0.0-rc.0",
"release": "6.3.0",
"rimraf": "^3.0.2",
"rollup": "2.36.1",

View File

@@ -1,7 +1,7 @@
{
"name": "blitz",
"description": "Blitz is a Rails-like framework for monolithic, full-stack React apps — built on Next.js",
"version": "0.45.2",
"version": "0.45.0-canary.0",
"license": "MIT",
"scripts": {
"test": "jest",
@@ -51,25 +51,25 @@
"url": "https://github.com/blitz-js/blitz"
},
"dependencies": {
"@blitzjs/cli": "0.45.2",
"@blitzjs/generator": "0.45.2",
"@blitzjs/server": "0.45.2",
"@blitzjs/cli": "0.45.0-canary.0",
"@blitzjs/generator": "0.45.0-canary.0",
"@blitzjs/server": "0.45.0-canary.0",
"@testing-library/jest-dom": "5.11.9",
"@testing-library/react": "11.2.5",
"@testing-library/react": "13.0.0-alpha.5",
"@testing-library/react-hooks": "^4.0.1",
"@types/jest": "26.0.20",
"chalk": "^4.1.0",
"cross-spawn": "7.0.3",
"debug": "4.3.1",
"envinfo": "^7.7.3",
"eslint-config-blitz": "0.45.2",
"eslint-config-blitz": "0.45.0-canary.0",
"jest": "^26.6.3",
"jest-watch-typeahead": "^0.6.1",
"minimist": "1.2.5",
"next": "0.45.2",
"next": "0.45.0-canary.0",
"os-name": "^4.0.0",
"pkg-dir": "^5.0.0",
"react-test-renderer": "17.0.1",
"react-test-renderer": "18.0.0-rc.0",
"resolve-from": "^5.0.0",
"symlink-dir": "4.1.0",
"ts-jest": "26.5.0"

View File

@@ -1,7 +1,7 @@
{
"name": "@blitzjs/cli",
"description": "Blitz.js CLI",
"version": "0.45.2",
"version": "0.45.0-canary.0",
"license": "MIT",
"scripts": {
"dev": "rimraf lib && tsc --watch --pretty --preserveWatchOutput",
@@ -22,9 +22,9 @@
"/lib"
],
"dependencies": {
"@blitzjs/generator": "0.45.2",
"@blitzjs/installer": "0.45.2",
"@blitzjs/server": "0.45.2",
"@blitzjs/generator": "0.45.0-canary.0",
"@blitzjs/installer": "0.45.0-canary.0",
"@blitzjs/server": "0.45.0-canary.0",
"@oclif/command": "1.8.0",
"@oclif/config": "1.17.0",
"@oclif/plugin-autocomplete": "0.3.0",

View File

@@ -2,15 +2,15 @@ import {
capitalize,
FormGenerator,
ModelGenerator,
ModelName,
modelName,
ModelNames,
modelNames,
MutationGenerator,
MutationsGenerator,
PageGenerator,
pluralCamel,
pluralPascal,
QueriesGenerator,
QueryGenerator,
singleCamel,
singlePascal,
uncapitalize,
} from "@blitzjs/generator"
import {flags} from "@oclif/command"
@@ -51,6 +51,19 @@ interface Args {
model: string
}
function modelName(input: string = "") {
return singleCamel(input)
}
function modelNames(input: string = "") {
return pluralCamel(input)
}
function ModelName(input: string = "") {
return singlePascal(input)
}
function ModelNames(input: string = "") {
return pluralPascal(input)
}
const generatorMap = {
[ResourceType.All]: [
PageGenerator,
@@ -241,7 +254,6 @@ export class Generate extends Command {
modelNames: modelNames(singularRootContext),
ModelName: ModelName(singularRootContext),
ModelNames: ModelNames(singularRootContext),
rawParentModelName: flags.parent,
parentModel: modelName(flags.parent),
parentModels: modelNames(flags.parent),
ParentModel: ModelName(flags.parent),

View File

@@ -1,6 +1,6 @@
{
"name": "@blitzjs/generator",
"version": "0.45.2",
"version": "0.45.0-canary.0",
"description": "File generation for the Blitz CLI",
"homepage": "https://github.com/blitz-js/blitz#readme",
"license": "MIT",
@@ -33,14 +33,13 @@
"dependencies": {
"@babel/core": "7.12.10",
"@babel/plugin-transform-typescript": "7.12.1",
"@blitzjs/server": "0.45.2",
"@blitzjs/server": "0.45.0-canary.0",
"@mrleebo/prisma-ast": "0.2.6",
"@types/jscodeshift": "0.11.2",
"chalk": "^4.1.0",
"cross-spawn": "7.0.3",
"diff": "5.0.0",
"enquirer": "2.3.6",
"fast-glob": "^3.1.1",
"fs-extra": "^9.1.0",
"got": "^11.8.1",
"jscodeshift": "0.13.0",

View File

@@ -3,7 +3,6 @@ import * as babel from "@babel/core"
import babelTransformTypescript from "@babel/plugin-transform-typescript"
import Enquirer from "enquirer"
import {EventEmitter} from "events"
import {escapePath} from "fast-glob"
import * as fs from "fs-extra"
import j from "jscodeshift"
import {create as createStore, Store} from "mem-fs"
@@ -13,8 +12,6 @@ import * as path from "path"
import getBabelOptions, {Overrides} from "recast/parsers/_babel_options"
import * as babelParser from "recast/parsers/babel"
import {ConflictChecker} from "./conflict-checker"
import {IBuilder} from "./generators/template-builders/builder"
import {NullBuilder} from "./generators/template-builders/null-builder"
import {pipe} from "./utils/pipe"
import {readdirRecursive} from "./utils/readdir-recursive"
const debug = require("debug")("blitz:generator")
@@ -163,12 +160,7 @@ export abstract class Generator<
if (!this.options.destinationRoot) this.options.destinationRoot = process.cwd()
}
public templateValuesBuilder: IBuilder<T, any> = NullBuilder
async getTemplateValues(): Promise<any> {
const values = await this.templateValuesBuilder.getTemplateValues(this.options)
return values
}
abstract getTemplateValues(): Promise<any>
abstract getTargetDirectory(): string
@@ -204,10 +196,6 @@ export abstract class Generator<
return result
}
public fieldTemplateRegExp: RegExp = new RegExp(
/({?\/\*\s*template: (.*) \*\/}?|\s*\/\/\s*template: (.*))/g,
)
process(
input: Buffer,
pathEnding: string,
@@ -223,21 +211,6 @@ export abstract class Generator<
if (codeFileExtensions.test(pathEnding)) {
templatedFile = this.replaceConditionals(inputStr, templateValues, prettierOptions || {})
}
const fieldTemplateString = templatedFile
.match(this.fieldTemplateRegExp)?.[0]
.replace(this.fieldTemplateRegExp, "$2$3")
if (fieldTemplateString) {
const fieldTemplatePosition = templatedFile.search(this.fieldTemplateRegExp)
templatedFile = [
templatedFile.slice(0, fieldTemplatePosition),
...(templateValues.fieldTemplateValues?.map((values: any) =>
this.replaceTemplateValues(fieldTemplateString, values),
) || []),
templatedFile.slice(fieldTemplatePosition),
].join("")
}
templatedFile = this.replaceTemplateValues(templatedFile, templateValues)
if (!this.useTs && tsExtension.test(pathEnding)) {
templatedFile =
@@ -286,34 +259,16 @@ export abstract class Generator<
pathSuffix = path.join(this.getTargetDirectory(), pathSuffix)
const templateValues = await this.getTemplateValues()
let sourcePath = this.sourcePath(filePath)
let destinationPath = this.destinationPath(pathSuffix)
this.fs.copy(this.sourcePath(filePath), this.destinationPath(pathSuffix), {
process: (input) =>
this.process(input, pathSuffix, templateValues, prettierOptions ?? undefined),
})
let templatedPathSuffix = this.replaceTemplateValues(pathSuffix, templateValues)
if (!this.useTs && tsExtension.test(this.destinationPath(pathSuffix))) {
templatedPathSuffix = templatedPathSuffix.replace(tsExtension, ".js")
}
let templatedDestinationPath = this.destinationPath(templatedPathSuffix)
const destinationExists = fs.existsSync(templatedDestinationPath)
if (destinationExists) {
const newContent = this.process(
this.fs.read(templatedDestinationPath, {raw: true}) as any,
pathSuffix,
templateValues,
prettierOptions ?? undefined,
)
this.fs.write(templatedDestinationPath, newContent)
} else {
this.fs.copy(escapePath(sourcePath), escapePath(destinationPath), {
process: (input) =>
this.process(input, pathSuffix, templateValues, prettierOptions ?? undefined),
})
if (templatedPathSuffix !== pathSuffix) {
this.fs.move(destinationPath, templatedDestinationPath)
}
if (templatedPathSuffix !== pathSuffix) {
this.fs.move(this.destinationPath(pathSuffix), this.destinationPath(templatedPathSuffix))
}
} catch (error) {
baseLogger({displayDateTime: false}).error(`Error generating ${filePath}`)

View File

@@ -3,10 +3,10 @@ import spawn from "cross-spawn"
import {readJSONSync, writeJson} from "fs-extra"
import {baseLogger, log} from "next/dist/server/lib/logging"
import {join} from "path"
import username from "username"
import {Generator, GeneratorOptions, SourceRootType} from "../generator"
import {fetchLatestVersionsFor} from "../utils/fetch-latest-version-for"
import {getBlitzDependencyVersion} from "../utils/get-blitz-dependency-version"
import {AppValuesBuilder} from "./template-builders/app-values-builder"
function assert(condition: any, message: string): asserts condition {
if (!condition) throw new Error(message)
@@ -30,11 +30,6 @@ export interface AppGeneratorOptions extends GeneratorOptions {
form?: "React Final Form" | "React Hook Form" | "Formik"
onPostInstall?: () => Promise<void>
}
export interface AppTemplateValues {
name: string,
safeNameSlug: string,
username: string | undefined
}
type PkgManager = "npm" | "yarn" | "pnpm"
export class AppGenerator extends Generator<AppGeneratorOptions> {
@@ -57,7 +52,13 @@ export class AppGenerator extends Generator<AppGeneratorOptions> {
return ["jsconfig.json", "jest.config.js", "package.js.json", "pre-push-js"]
}
templateValuesBuilder = new AppValuesBuilder(this.fs)
async getTemplateValues() {
return {
name: this.options.appName,
safeNameSlug: this.options.appName.replace(/[^a-zA-Z0-9-_]/g, "-"),
username: await username(),
}
}
getTargetDirectory() {
return ""

View File

@@ -1,9 +1,17 @@
import {FieldValuesBuilder, ResourceGeneratorOptions} from ".."
import {Generator, SourceRootType} from "../generator"
import {Generator, GeneratorOptions, SourceRootType} from "../generator"
import {getTemplateRoot} from "../utils/get-template-root"
import {camelCaseToKebabCase} from "../utils/inflector"
export interface FormGeneratorOptions extends ResourceGeneratorOptions {}
export interface FormGeneratorOptions extends GeneratorOptions {
ModelName: string
ModelNames: string
modelName: string
modelNames: string
parentModel?: string
parentModels?: string
ParentModel?: string
ParentModels?: string
}
export class FormGenerator extends Generator<FormGeneratorOptions> {
sourceRoot: SourceRootType
@@ -14,7 +22,33 @@ export class FormGenerator extends Generator<FormGeneratorOptions> {
static subdirectory = "queries"
templateValuesBuilder = new FieldValuesBuilder()
private getId(input: string = "") {
if (!input) return input
return `${input}Id`
}
private getParam(input: string = "") {
if (!input) return input
return `[${input}]`
}
// eslint-disable-next-line require-await
async getTemplateValues() {
return {
parentModelId: this.getId(this.options.parentModel),
parentModelParam: this.getParam(this.getId(this.options.parentModel)),
parentModel: this.options.parentModel,
parentModels: this.options.parentModels,
ParentModel: this.options.ParentModel,
ParentModels: this.options.ParentModels,
modelId: this.getId(this.options.modelName),
modelIdParam: this.getParam(this.getId(this.options.modelName)),
modelName: this.options.modelName,
modelNames: this.options.modelNames,
ModelName: this.options.ModelName,
ModelNames: this.options.ModelNames,
}
}
getTargetDirectory() {
const context = this.options.context ? `${camelCaseToKebabCase(this.options.context)}/` : ""

View File

@@ -1,11 +1,11 @@
import * as ast from "@mrleebo/prisma-ast"
import {spawn} from "cross-spawn"
import {log,newline} from "next/dist/server/lib/logging"
import {baseLogger, log, newline} from "next/dist/server/lib/logging"
import which from "npm-which"
import path from "path"
import {Generator, GeneratorOptions, SourceRootType} from "../generator"
import {Field} from "../prisma/field"
import {Model} from "../prisma/model"
import {getPrismaSchema} from "../utils/get-prisma-schema"
import {getTemplateRoot} from "../utils/get-template-root"
export interface ModelGeneratorOptions extends GeneratorOptions {
@@ -23,6 +23,8 @@ export class ModelGenerator extends Generator<ModelGeneratorOptions> {
static subdirectory = "../.."
unsafe_disableConflictChecker = true
async getTemplateValues() {}
getTargetDirectory() {
return ""
}
@@ -39,15 +41,26 @@ export class ModelGenerator extends Generator<ModelGeneratorOptions> {
// eslint-disable-next-line require-await
async write() {
const {schema, schemaPath} = getPrismaSchema(this.fs)
const schemaPath = path.resolve("db/schema.prisma")
if (!this.fs.exists(schemaPath)) {
throw new Error("Prisma schema file was not found")
}
let schema: ast.Schema
try {
schema = ast.getSchema(this.fs.read(schemaPath))
} catch (err) {
baseLogger({displayDateTime: false}).error("Failed to parse db/schema.prisma file")
throw err
}
const {modelName, extraArgs, dryRun} = this.options
let updatedOrCreated = "created"
let fieldPromises = (extraArgs.length === 1 && extraArgs[0].includes(" ")
let fields = (extraArgs.length === 1 && extraArgs[0].includes(" ")
? extraArgs[0].split(" ")
: extraArgs
).map((input) => Field.parse(input, schema))
let fields = (await Promise.all(fieldPromises)).flatMap(fieldArray => fieldArray)
).flatMap((input) => Field.parse(input, schema))
const modelDefinition = new Model(modelName, fields)
let model: ast.Model | undefined
@@ -86,13 +99,10 @@ export class ModelGenerator extends Generator<ModelGeneratorOptions> {
}
async postWrite() {
const prismaBin = which(process.cwd()).sync("prisma")
//@ts-ignore
spawn.sync(prismaBin, ["format"], {stdio: "inherit"})
const shouldMigrate = await this.prismaMigratePrompt()
if (shouldMigrate) {
await new Promise<void>((res, rej) => {
const prismaBin = which(process.cwd()).sync("prisma")
const child = spawn(prismaBin, ["migrate", "dev"], {stdio: "inherit"})
child.on("exit", (code) => (code === 0 ? res() : rej()))
})

View File

@@ -1,9 +1,17 @@
import {FieldValuesBuilder, ResourceGeneratorOptions} from ".."
import {Generator, SourceRootType} from "../generator"
import {Generator, GeneratorOptions, SourceRootType} from "../generator"
import {getTemplateRoot} from "../utils/get-template-root"
import {camelCaseToKebabCase} from "../utils/inflector"
export interface MutationsGeneratorOptions extends ResourceGeneratorOptions {}
export interface MutationsGeneratorOptions extends GeneratorOptions {
ModelName: string
ModelNames: string
modelName: string
modelNames: string
parentModel?: string
parentModels?: string
ParentModel?: string
ParentModels?: string
}
export class MutationsGenerator extends Generator<MutationsGeneratorOptions> {
sourceRoot: SourceRootType
@@ -13,7 +21,33 @@ export class MutationsGenerator extends Generator<MutationsGeneratorOptions> {
}
static subdirectory = "mutations"
templateValuesBuilder = new FieldValuesBuilder(this.fs)
private getId(input: string = "") {
if (!input) return input
return `${input}Id`
}
private getParam(input: string = "") {
if (!input) return input
return `[${input}]`
}
// eslint-disable-next-line require-await
async getTemplateValues() {
return {
parentModelId: this.getId(this.options.parentModel),
parentModelParam: this.getParam(this.getId(this.options.parentModel)),
parentModel: this.options.parentModel,
parentModels: this.options.parentModels,
ParentModel: this.options.ParentModel,
ParentModels: this.options.ParentModels,
modelId: this.getId(this.options.modelName),
modelIdParam: this.getParam(this.getId(this.options.modelName)),
modelName: this.options.modelName,
modelNames: this.options.modelNames,
ModelName: this.options.ModelName,
ModelNames: this.options.ModelNames,
}
}
getTargetDirectory() {
const context = this.options.context ? `${camelCaseToKebabCase(this.options.context)}/` : ""

View File

@@ -1,9 +1,17 @@
import {FieldValuesBuilder, ResourceGeneratorOptions} from ".."
import {Generator, SourceRootType} from "../generator"
import {Generator, GeneratorOptions, SourceRootType} from "../generator"
import {getTemplateRoot} from "../utils/get-template-root"
import {camelCaseToKebabCase} from "../utils/inflector"
export interface PageGeneratorOptions extends ResourceGeneratorOptions {}
export interface PageGeneratorOptions extends GeneratorOptions {
ModelName: string
ModelNames: string
modelName: string
modelNames: string
parentModel?: string
parentModels?: string
ParentModel?: string
ParentModels?: string
}
export class PageGenerator extends Generator<PageGeneratorOptions> {
sourceRoot: SourceRootType
@@ -13,7 +21,42 @@ export class PageGenerator extends Generator<PageGeneratorOptions> {
}
static subdirectory = "pages"
templateValuesBuilder = new FieldValuesBuilder(this.fs)
private getId(input: string = "") {
if (!input) return input
return `${input}Id`
}
private getParam(input: string = "") {
if (!input) return input
return `[${input}]`
}
// eslint-disable-next-line require-await
async getTemplateValues() {
return {
parentModelId: this.getId(this.options.parentModel),
parentModelParam: this.getParam(this.getId(this.options.parentModel)),
parentModel: this.options.parentModel,
parentModels: this.options.parentModels,
ParentModel: this.options.ParentModel,
ParentModels: this.options.ParentModels,
modelId: this.getId(this.options.modelName),
modelIdParam: this.getParam(this.getId(this.options.modelName)),
modelName: this.options.modelName,
modelNames: this.options.modelNames,
ModelName: this.options.ModelName,
ModelNames: this.options.ModelNames,
modelNamesPath: this.getModelNamesPath(),
}
}
getModelNamesPath() {
const kebabCaseContext = this.options.context
? `${camelCaseToKebabCase(this.options.context)}/`
: ""
const kebabCaseModelNames = camelCaseToKebabCase(this.options.modelNames)
return kebabCaseContext + kebabCaseModelNames
}
getTargetDirectory() {
const kebabCaseModelName = camelCaseToKebabCase(this.options.modelNames)

View File

@@ -1,9 +1,17 @@
import {FieldValuesBuilder, ResourceGeneratorOptions} from ".."
import {Generator, SourceRootType} from "../generator"
import {Generator, GeneratorOptions, SourceRootType} from "../generator"
import {getTemplateRoot} from "../utils/get-template-root"
import {camelCaseToKebabCase} from "../utils/inflector"
export interface QueriesGeneratorOptions extends ResourceGeneratorOptions {}
export interface QueriesGeneratorOptions extends GeneratorOptions {
ModelName: string
ModelNames: string
modelName: string
modelNames: string
parentModel?: string
parentModels?: string
ParentModel?: string
ParentModels?: string
}
export class QueriesGenerator extends Generator<QueriesGeneratorOptions> {
sourceRoot: SourceRootType
@@ -13,7 +21,33 @@ export class QueriesGenerator extends Generator<QueriesGeneratorOptions> {
}
static subdirectory = "queries"
templateValuesBuilder = new FieldValuesBuilder(this.fs)
private getId(input: string = "") {
if (!input) return input
return `${input}Id`
}
private getParam(input: string = "") {
if (!input) return input
return `[${input}]`
}
// eslint-disable-next-line require-await
async getTemplateValues() {
return {
parentModelId: this.getId(this.options.parentModel),
parentModelParam: this.getParam(this.getId(this.options.parentModel)),
parentModel: this.options.parentModel,
parentModels: this.options.parentModels,
ParentModel: this.options.ParentModel,
ParentModels: this.options.ParentModels,
modelId: this.getId(this.options.modelName),
modelIdParam: this.getParam(this.getId(this.options.modelName)),
modelName: this.options.modelName,
modelNames: this.options.modelNames,
ModelName: this.options.ModelName,
ModelNames: this.options.ModelNames,
}
}
getTargetDirectory() {
const context = this.options.context ? `${camelCaseToKebabCase(this.options.context)}/` : ""

View File

@@ -1,14 +0,0 @@
import username from "username"
import {AppGeneratorOptions, AppTemplateValues} from "../.."
import {Builder} from "./builder"
export class AppValuesBuilder extends Builder<AppGeneratorOptions, AppTemplateValues> {
public async getTemplateValues(options: AppGeneratorOptions): Promise<AppTemplateValues> {
const values = {
name: options.appName,
safeNameSlug: options.appName.replace(/[^a-zA-Z0-9-_]/g, "-"),
username: await username(),
}
return values
}
}

View File

@@ -1,118 +0,0 @@
import {Editor} from "mem-fs-editor"
import {CodegenField} from "next/dist/server/config-shared"
import {GeneratorOptions} from "../../generator"
import {getCodegen, getResourceValueFromCodegen} from "../../utils/get-codegen"
import {
addSpaceBeforeCapitals,
camelCaseToKebabCase,
singleCamel,
singlePascal,
} from "../../utils/inflector"
export interface IBuilder<T, U> {
getTemplateValues(Options: T): Promise<U>
}
export interface ResourceGeneratorOptions extends GeneratorOptions {
ModelName: string
ModelNames: string
modelName: string
modelNames: string
rawParentModelName?: string
parentModel?: string
parentModels?: string
ParentModel?: string
ParentModels?: string
extraArgs?: string[]
}
export interface CommonTemplateValues {
parentModelId: string
parentModelParam: string
parentModel?: string
parentModels?: string
ParentModel?: string
ParentModels?: string
parentModelIdZodType?: string
modelId: string
modelIdZodType?: string
modelIdParam: string
modelName: string
modelNames: string
ModelName: string
ModelNames: string
modelNamesPath: string
fieldTemplateValues?: {[x: string]: any}
}
export abstract class Builder<T, U> implements IBuilder<T, U> {
public constructor(fs?: Editor) {
this.fs = fs
}
abstract getTemplateValues(Options: T): Promise<U>
public fs: Editor | undefined
public defaultFieldConfig: CodegenField = {
component: "LabeledTextField",
inputType: "text",
zodType: "string",
prismaType: "String",
}
public getId(input: string = "") {
if (!input) return input
return `${input}Id`
}
public getParam(input: string = "") {
if (!input) return input
return `[${input}]`
}
public getModelNamesPath(context: string | undefined, modelNames: string) {
const kebabCaseContext = context ? `${camelCaseToKebabCase(context)}/` : ""
const kebabCaseModelNames = camelCaseToKebabCase(modelNames)
return kebabCaseContext + kebabCaseModelNames
}
// eslint-disable-next-line require-await
public async getZodType(type: string = "") {
return getResourceValueFromCodegen(type, "zodType")
}
// eslint-disable-next-line require-await
public async getComponentForType(type: string = "") {
return getResourceValueFromCodegen(type, "component")
}
// eslint-disable-next-line require-await
public async getInputType(type: string = "") {
return getResourceValueFromCodegen(type, "inputType")
}
// eslint-disable-next-line require-await
public async getFieldTemplateValues(args: string[]) {
const argsPromises = args.map(async (arg: string) => {
let [valueName, typeName] = arg.split(":")
if (typeName.includes("?")) {
typeName = typeName.replace("?", "")
}
let values = {
attributeName: singleCamel(valueName),
fieldName: singleCamel(valueName),
FieldName: singlePascal(valueName),
field_name: addSpaceBeforeCapitals(valueName).toLocaleLowerCase(), // field name
Field_name: singlePascal(addSpaceBeforeCapitals(valueName).toLocaleLowerCase()), // Field name
Field_Name: singlePascal(addSpaceBeforeCapitals(valueName)), // Field Name
}
const codegen = await getCodegen()
// iterate over resources defined for this field type
const fieldConfig = codegen.fieldTypeMap?.[typeName] || this.defaultFieldConfig
values = {...values, ...fieldConfig}
return values
})
return Promise.all(argsPromises)
}
}

View File

@@ -1,117 +0,0 @@
import * as ast from "@mrleebo/prisma-ast"
import {create as createStore} from "mem-fs"
import {create as createEditor, Editor} from "mem-fs-editor"
import {getResourceValueFromCodegen} from "../../utils/get-codegen"
import {getPrismaSchema} from "../../utils/get-prisma-schema"
import {ModelName, modelName, ModelNames, modelNames} from "../../utils/model-names"
import {Builder, CommonTemplateValues, ResourceGeneratorOptions} from "./builder"
export class FieldValuesBuilder extends Builder<ResourceGeneratorOptions, CommonTemplateValues> {
private getEditor = (): Editor => {
if (this.fs !== undefined) {
return this.fs
}
const store = createStore()
this.fs = createEditor(store)
return this.fs
}
// eslint-disable-next-line require-await
public async getTemplateValues(options: ResourceGeneratorOptions): Promise<CommonTemplateValues> {
const values: CommonTemplateValues = {
parentModelId: this.getId(options.parentModel),
parentModelIdZodType: undefined,
parentModelParam: this.getParam(this.getId(options.parentModel)),
parentModel: options.parentModel,
parentModels: options.parentModels,
ParentModel: options.ParentModel,
ParentModels: options.ParentModels,
modelId: this.getId(options.modelName),
modelIdZodType: "number",
modelIdParam: this.getParam(this.getId(options.modelName)),
modelName: options.modelName,
modelNames: options.modelNames,
ModelName: options.ModelName,
ModelNames: options.ModelNames,
modelNamesPath: this.getModelNamesPath(options.context, options.modelNames),
}
if (options.extraArgs) {
// specialArgs - these are arguments like 'id' or 'belongsTo', which are not meant to
// be processed as fields but have their own special logic
let specialArgs: {[key in string]: string} = {}
const processSpecialArgs: Promise<void>[] = options.extraArgs.map(async (arg) => {
const [valueName, typeName] = arg.split(":")
if (valueName === "id") {
values.modelIdZodType = await this.getZodType(typeName)
specialArgs[arg] = "present"
}
if (valueName === "belongsTo") {
// TODO: Determine how this is done. The model will generate with a field with the id name
// and type of the parent of this model, and forms etc. should
// In addition, need to do the same logic that the options.parentModel != undefined below does
specialArgs[arg] = "present"
process.env.parentModel = typeName
options.rawParentModelName = typeName
options.parentModel = modelName(typeName)
options.parentModels = modelNames(typeName)
options.ParentModel = ModelName(typeName)
options.ParentModels = ModelNames(typeName)
}
})
await Promise.all(processSpecialArgs)
// Filter out special args by making sure the argument isn't present in the list
const nonSpecialArgs = options.extraArgs.filter((arg) => specialArgs[arg] !== "present")
// Get the parent model it type if options.parentModel exists
if (options.parentModel !== undefined && options.parentModel.length > 0) {
const {schema} = getPrismaSchema(this.getEditor())
// O(N) - N is total ast Blocks
const model = schema.list.find(function (component): component is ast.Model {
return component.type === "model" && component.name === options.rawParentModelName
})
if (model !== undefined) {
// O(N) - N is number of properties in parent model
const idField = model.properties.find(function (property): property is ast.Field {
return (
property.type === "field" &&
property.attributes?.findIndex((attr) => attr.name === "id") !== -1
)
})
// TODO: Do we want a map between prisma types and "user types", we can then use that map instead of these conditionals
// We have a map from "user types" (which are what users type into the blitz generate command)
// to primsa type and other types, but we dont have a reverse map 1:1. This is because we lose
// some information for certain maps. E.g.: fieldname:uuid will be converted into a Prisma field with
// the String type, and the uuid portion is added to a decorator at the end of the field.
// This means it is more complicated to extract the original "user specified type" than creating a reverse map
if (idField?.fieldType === "Int") {
// TODO: Check if ints have decorators that make them a different type, like Bigint, etc.
// And see if that has to map to a different user specified type
values.parentModelIdZodType = await getResourceValueFromCodegen("int", "zodType")
} else if (idField?.fieldType === "String") {
if (
idField.attributes?.find(
(attr) =>
attr.name === "default" &&
attr.args?.findIndex((arg) => arg.value === "uuid") !== -1,
)
) {
values.parentModelIdZodType = await getResourceValueFromCodegen("uuid", "zodType")
} else {
values.parentModelIdZodType = await getResourceValueFromCodegen("string", "zodType")
}
}
} else {
// TODO: handle scenario where parent wasnt found in existing schema. Should we throw an error, or a warning asking the user to verify that the parent model exists?
}
}
if (nonSpecialArgs.length > 0) {
const ftv = await this.getFieldTemplateValues(nonSpecialArgs)
return {...values, fieldTemplateValues: ftv}
}
}
return values
}
}

View File

@@ -1,8 +0,0 @@
import {IBuilder} from "./builder"
export const NullBuilder: IBuilder<any,any> = {
// eslint-disable-next-line require-await
getTemplateValues: async () => {
return {}
},
}

View File

@@ -8,11 +8,6 @@ export * from "./generators/query-generator"
export * from "./generators/form-generator"
export * from "./generator"
export * from "./conflict-checker"
export * from "./generators/template-builders/builder"
export * from "./generators/template-builders/null-builder"
export * from "./generators/template-builders/app-values-builder"
export * from "./generators/template-builders/field-values-builder"
export * from "./utils/model-names"
export {getLatestVersion} from "./utils/get-latest-version"
export {
singleCamel,
@@ -21,5 +16,4 @@ export {
pluralPascal,
capitalize,
uncapitalize,
addSpaceBeforeCapitals,
} from "./utils/inflector"

View File

@@ -1,8 +1,6 @@
import * as ast from "@mrleebo/prisma-ast"
import {baseLogger, log} from "next/dist/server/lib/logging"
import {getResourceConfigFromCodegen} from "../utils/get-codegen"
import {capitalize, singlePascal, uncapitalize} from "../utils/inflector"
const debug = require("debug")("blitz:field")
export enum FieldType {
Boolean = "Boolean",
@@ -57,39 +55,25 @@ export class Field {
relationToFields?: string[]
// 'name:type?[]:attribute' => Field
static async parse(input: string, schema?: ast.Schema): Promise<Field[]> {
debug(`parsing "Field" for input ${input}`)
static parse(input: string, schema?: ast.Schema): Field[] {
const [_fieldName, _fieldType = "String", _attribute] = input.split(":")
let attribute = _attribute
let fieldName = uncapitalize(_fieldName)
let fieldType = capitalize(_fieldType)
// Check if it would make sense to expose that to users as well?
// Also in the case of a relationship, need to use the raw model name, cant capitalize it.
const isId = fieldName === "id"
let isRequired = true
let isList = false
let isUpdatedAt = false
let isUnique = false
let defaultValue = undefined
let relationFromFields = undefined
let relationToFields = undefined
let maybeIdField = undefined
let isUnique = false
if (fieldType.includes("?")) {
fieldType = fieldType.replace("?", "")
isRequired = false
}
const {prismaType, default: defaultConfigValue} =
(await Field.getConfigForPrismaType(fieldType)) ?? {}
if (prismaType) {
fieldType = prismaType
}
if (defaultConfigValue) {
attribute = `default=${defaultConfigValue}`
}
if (fieldType.includes("[]")) {
fieldType = fieldType.replace("[]", "")
fieldName = uncapitalize(fieldName)
@@ -179,10 +163,6 @@ export class Field {
}
}
public static getConfigForPrismaType = async (fieldType: string) => {
return await getResourceConfigFromCodegen(fieldType.toLowerCase())
}
constructor(name: string, options: FieldArgs) {
if (!name) throw new MissingFieldNameError("[PrismaField]: A field name is required")
if (!options.type) {

View File

@@ -1,101 +0,0 @@
import {CodegenConfig, CodegenField, NextConfigComplete} from "next/dist/server/config-shared"
import {baseLogger} from "next/dist/server/lib/logging"
export const defaultCodegenConfig: CodegenConfig = {
fieldTypeMap: {
string: {
component: "LabeledTextField",
inputType: "text",
zodType: "string",
prismaType: "String",
},
boolean: {
component: "LabeledTextField",
inputType: "text",
zodType: "boolean",
prismaType: "Boolean",
},
int: {
component: "LabeledTextField",
inputType: "number",
zodType: "number",
prismaType: "Int",
},
number: {
component: "LabeledTextField",
inputType: "number",
zodType: "number",
prismaType: "Int",
},
bigint: {
component: "LabeledTextField",
inputType: "number",
zodType: "number",
prismaType: "BigInt",
},
float: {
component: "LabeledTextField",
inputType: "number",
zodType: "number",
prismaType: "Float",
},
decimal: {
component: "LabeledTextField",
inputType: "number",
zodType: "number",
prismaType: "Decimal",
},
datetime: {
component: "LabeledTextField",
inputType: "text",
zodType: "string",
prismaType: "DateTime",
},
uuid: {
component: "LabeledTextField",
inputType: "text",
zodType: "string().uuid",
prismaType: "String",
default: "uuid",
},
json: {
component: "LabeledTextField",
inputType: "text",
zodType: "any",
prismaType: "Json",
},
},
}
export const getResourceValueFromCodegen = async (
fieldType: string,
resource: keyof CodegenField,
): Promise<string | undefined> => {
const codegen = await getCodegen()
const templateValue = codegen.fieldTypeMap?.[fieldType]?.[resource]
return templateValue
}
export const getResourceConfigFromCodegen = async (
fieldType: string,
): Promise<CodegenField | undefined> => {
const codegen = await getCodegen()
const config = codegen.fieldTypeMap?.[fieldType]
return config
}
export const getCodegen = async (): Promise<NextConfigComplete["codegen"]> => {
try {
const {loadConfigAtRuntime} = await import("next/dist/server/config-shared")
const config = await loadConfigAtRuntime()
if (config.codegen !== undefined) {
// TODO: potentially verify that codegen is well formed using zod
return config.codegen
}
return defaultCodegenConfig
} catch (ex) {
baseLogger({displayDateTime: false}).warn("Failed loading config from blitz.config file " + ex)
return defaultCodegenConfig
}
}

View File

@@ -1,20 +0,0 @@
import * as ast from "@mrleebo/prisma-ast"
import {Editor} from "mem-fs-editor"
import { baseLogger } from "next/dist/server/lib/logging"
import path from "path"
export const getPrismaSchema = (memFsEditor : Editor): {schema: ast.Schema, schemaPath: string} => {
const schemaPath = path.resolve("db/schema.prisma")
if (!memFsEditor.exists(schemaPath)) {
throw new Error("Prisma schema file was not found")
}
let schema: ast.Schema
try {
schema = ast.getSchema(memFsEditor.read(schemaPath))
} catch (err) {
baseLogger({displayDateTime: false}).error("Failed to parse db/schema.prisma file")
throw err
}
return {schema, schemaPath}
}

View File

@@ -25,7 +25,3 @@ export const pluralCamel = pipe(plural, uncapitalize)
export function camelCaseToKebabCase(transformString: string) {
return transformString.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, "$1-$2").toLowerCase()
}
export function addSpaceBeforeCapitals(input: string): string {
return singleCamel(input).replace(/(?!^)([A-Z])/g, " $1")
}

View File

@@ -1,14 +0,0 @@
import {pluralCamel, pluralPascal, singleCamel, singlePascal} from "../index"
export function modelName(input: string = "") {
return singleCamel(input)
}
export function modelNames(input: string = "") {
return pluralCamel(input)
}
export function ModelName(input: string = "") {
return singlePascal(input)
}
export function ModelNames(input: string = "") {
return pluralPascal(input)
}

View File

@@ -6,7 +6,7 @@ const config: BlitzConfig = {
cookiePrefix: "__safeNameSlug__",
isAuthorized: simpleRolesIsAuthorized,
}),
],
],
/* Uncomment this to customize the webpack config
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
// Note: we provide webpack above so you should not `require` it
@@ -14,6 +14,6 @@ const config: BlitzConfig = {
// Important: return the modified config
return config
},
*/
*/
}
module.exports = config

View File

@@ -24,8 +24,8 @@
"dependencies": {
"@prisma/client": "3.x",
"blitz": "latest",
"react-dom": "18.0.0-alpha-5ca4b0433-20211020",
"react": "18.0.0-beta-149b420f6-20211119",
"react": "18.0.0-rc.0",
"react-dom": "18.0.0-rc.0",
"zod": "3.x"
},
"devDependencies": {

View File

@@ -26,13 +26,14 @@
"dependencies": {
"@prisma/client": "3.x",
"blitz": "latest",
"react-dom": "18.0.0-alpha-5ca4b0433-20211020",
"react": "18.0.0-beta-149b420f6-20211119",
"react": "18.0.0-rc.0",
"react-dom": "18.0.0-rc.0",
"zod": "3.x"
},
"devDependencies": {
"@types/preview-email": "2.x",
"@types/react": "17.x",
"@types/react-dom": "17.x",
"eslint": "7.x",
"husky": "7.x",
"lint-staged": "11.x",

View File

@@ -6,7 +6,7 @@ export {FORM_ERROR} from "app/core/components/Form"
export function __ModelName__Form<S extends z.ZodType<any, any>>(props: FormProps<S>) {
return (
<Form<S> {...props}>
{/* template: <__component__ name="__fieldName__" label="__Field_Name__" placeholder="__Field_Name__" type="__inputType__" /> */}
<LabeledTextField name="name" label="Name" placeholder="Name" />
</Form>
)
}

View File

@@ -19,8 +19,8 @@
},
"dependencies": {
"blitz": "latest",
"react-dom": "18.0.0-alpha-5ca4b0433-20211020",
"react": "18.0.0-beta-149b420f6-20211119"
"react": "18.0.0-rc.0",
"react-dom": "18.0.0-rc.0"
},
"devDependencies": {
"eslint": "7.x",

View File

@@ -21,11 +21,12 @@
},
"dependencies": {
"blitz": "latest",
"react-dom": "18.0.0-alpha-5ca4b0433-20211020",
"react": "18.0.0-beta-149b420f6-20211119"
"react": "18.0.0-rc.0",
"react-dom": "18.0.0-rc.0"
},
"devDependencies": {
"@types/react": "17.x",
"@types/react-dom": "17.x",
"eslint": "7.x",
"husky": "7.x",
"lint-staged": "11.x",

View File

@@ -4,12 +4,12 @@ import {z} from "zod"
if (process.env.parentModel) {
const Create__ModelName__ = z.object({
__parentModelId__: z.__parentModelIdZodType__(),
// template: __fieldName__: z.__zodType__(),
name: z.string(),
__parentModelId__: z.number()
})
} else {
const Create__ModelName__ = z.object({
// template: __fieldName__: z.__zodType__(),
name: z.string(),
})
}

View File

@@ -3,7 +3,7 @@ import db from "db"
import {z} from "zod"
const Delete__ModelName__ = z.object({
id: z.__modelIdZodType__(),
id: z.number(),
})
export default resolver.pipe(

View File

@@ -3,8 +3,8 @@ import db from "db"
import {z} from "zod"
const Update__ModelName__ = z.object({
id: z.__modelIdZodType__(),
// template: __fieldName__: z.__zodType__(),
id: z.number(),
name: z.string(),
})
export default resolver.pipe(

View File

@@ -1,223 +0,0 @@
import {FieldValuesBuilder} from "../../src/generators/template-builders/field-values-builder"
describe("Form Generator", () => {
process.env.BLITZ_APP_DIR = process.cwd()
const generator = new FieldValuesBuilder()
it("Should work with simple types", async () => {
expect(
await generator.getFieldTemplateValues(["field1:string", "field2:string"]),
).toStrictEqual([
{
component: "LabeledTextField",
FieldName: "Field1",
Field_Name: "Field1",
Field_name: "Field1",
attributeName: "field1",
fieldName: "field1",
field_name: "field1",
zodType: "string",
prismaType: "String",
inputType: "text",
},
{
component: "LabeledTextField",
FieldName: "Field2",
Field_Name: "Field2",
Field_name: "Field2",
attributeName: "field2",
fieldName: "field2",
field_name: "field2",
zodType: "string",
prismaType: "String",
inputType: "text",
},
])
})
it("Should work with optional types", async () => {
expect(
await generator.getFieldTemplateValues(["field1:string?", "field2:number"]),
).toStrictEqual([
{
component: "LabeledTextField",
FieldName: "Field1",
Field_Name: "Field1",
Field_name: "Field1",
attributeName: "field1",
fieldName: "field1",
field_name: "field1",
zodType: "string",
prismaType: "String",
inputType: "text",
},
{
component: "LabeledTextField",
FieldName: "Field2",
Field_Name: "Field2",
Field_name: "Field2",
attributeName: "field2",
fieldName: "field2",
field_name: "field2",
zodType: "number",
prismaType: "Int",
inputType: "number",
},
])
})
it("Should work with default values", async () => {
expect(await generator.getFieldTemplateValues(["field1:string:default='test'"])).toStrictEqual([
{
component: "LabeledTextField",
FieldName: "Field1",
Field_Name: "Field1",
Field_name: "Field1",
attributeName: "field1",
fieldName: "field1",
field_name: "field1",
zodType: "string",
prismaType: "String",
inputType: "text",
},
])
})
it("Should work with different input types", async () => {
const fields = [
"field1:string?",
"field2:boolean",
"field3:int",
"field4:number",
"field5:bigint?",
"field6:float",
"field7:decimal",
"field8:datetime",
"field9:uuid",
"field10:json?",
]
expect(await generator.getFieldTemplateValues(fields)).toStrictEqual([
{
component: "LabeledTextField",
FieldName: "Field1",
Field_Name: "Field1",
Field_name: "Field1",
attributeName: "field1",
fieldName: "field1",
field_name: "field1",
zodType: "string",
prismaType: "String",
inputType: "text",
},
{
component: "LabeledTextField",
FieldName: "Field2",
Field_Name: "Field2",
Field_name: "Field2",
attributeName: "field2",
fieldName: "field2",
field_name: "field2",
zodType: "boolean",
prismaType: "Boolean",
inputType: "text",
},
{
component: "LabeledTextField",
FieldName: "Field3",
Field_Name: "Field3",
Field_name: "Field3",
attributeName: "field3",
fieldName: "field3",
field_name: "field3",
zodType: "number",
prismaType: "Int",
inputType: "number",
},
{
component: "LabeledTextField",
FieldName: "Field4",
Field_Name: "Field4",
Field_name: "Field4",
attributeName: "field4",
fieldName: "field4",
field_name: "field4",
zodType: "number",
prismaType: "Int",
inputType: "number",
},
{
component: "LabeledTextField",
FieldName: "Field5",
Field_Name: "Field5",
Field_name: "Field5",
attributeName: "field5",
fieldName: "field5",
field_name: "field5",
zodType: "number",
prismaType: "BigInt",
inputType: "number",
},
{
component: "LabeledTextField",
FieldName: "Field6",
Field_Name: "Field6",
Field_name: "Field6",
attributeName: "field6",
fieldName: "field6",
field_name: "field6",
zodType: "number",
prismaType: "Float",
inputType: "number",
},
{
component: "LabeledTextField",
FieldName: "Field7",
Field_Name: "Field7",
Field_name: "Field7",
attributeName: "field7",
fieldName: "field7",
field_name: "field7",
zodType: "number",
prismaType: "Decimal",
inputType: "number",
},
{
component: "LabeledTextField",
FieldName: "Field8",
Field_Name: "Field8",
Field_name: "Field8",
attributeName: "field8",
fieldName: "field8",
field_name: "field8",
zodType: "string",
prismaType: "DateTime",
inputType: "text",
},
{
component: "LabeledTextField",
FieldName: "Field9",
Field_Name: "Field9",
Field_name: "Field9",
attributeName: "field9",
fieldName: "field9",
field_name: "field9",
zodType: "string().uuid",
prismaType: "String",
inputType: "text",
default: "uuid",
},
{
component: "LabeledTextField",
FieldName: "Field10",
Field_Name: "Field10",
Field_name: "Field10",
attributeName: "field10",
fieldName: "field10",
field_name: "field10",
zodType: "any",
prismaType: "Json",
inputType: "text",
},
])
})
})

View File

@@ -1,47 +0,0 @@
import {FormGenerator} from "../../src/generators/form-generator"
describe("Form Generator", () => {
process.env.BLITZ_APP_DIR = process.cwd()
const generator = new FormGenerator({
ModelName: "project",
ModelNames: "projects",
modelName: "project",
modelNames: "projects",
extraArgs: ["myProjectName:string"],
})
it("Correctly generates field names", async () => {
const templateValues = await generator.getTemplateValues()
expect(templateValues.fieldTemplateValues[0].fieldName).toEqual("myProjectName")
expect(templateValues.fieldTemplateValues[0].FieldName).toEqual("MyProjectName")
expect(templateValues.fieldTemplateValues[0].field_name).toEqual("my project name")
expect(templateValues.fieldTemplateValues[0].Field_name).toEqual("My project name")
expect(templateValues.fieldTemplateValues[0].Field_Name).toEqual("My Project Name")
})
it("matches template comments correctly", () => {
const regex = generator.fieldTemplateRegExp
const curlyBraceComment1 = `{/* template: <__component__ name="__fieldName__" label="__Field_Name__" placeholder="__Field_Name__" /> */}`
expect(curlyBraceComment1.match(regex)?.[0].replace(regex, "$2$3")).toBe(
`<__component__ name="__fieldName__" label="__Field_Name__" placeholder="__Field_Name__" />`,
)
expect(curlyBraceComment1.match(regex)?.[0].replace(regex, "$2$3")).not.toBe(`something Random`)
const normalComment1 = `// template: __fieldName__: z.__zodType__(),`
expect(normalComment1.match(regex)?.[0].replace(regex, "$2$3")).toBe(
`__fieldName__: z.__zodType__(),`,
)
expect(normalComment1.match(regex)?.[0].replace(regex, "$2$3")).not.toBe(`something Random`)
const commentWithSpacing = `// template: __fieldName__: z.__zodType__(),`
const commentWithNoSpacing = `//template: __fieldName__: z.__zodType__(),`
expect(commentWithSpacing.match(regex)?.[0].replace(regex, "$2$3")).toBe(
`__fieldName__: z.__zodType__(),`,
)
expect(commentWithNoSpacing.match(regex)?.[0].replace(regex, "$2$3")).toBe(
`__fieldName__: z.__zodType__(),`,
)
})
})

View File

@@ -9,10 +9,8 @@ describe("PageGenerator", () => {
})
describe("#getModelNamesPath", () => {
it("returns path only with default modelNames", async () => {
expect((await generator.getTemplateValues()).modelNamesPath).toBe(
"projects",
)
it("returns path only with default modelNames", () => {
expect(generator.getModelNamesPath()).toEqual("projects")
})
describe("when generator has context option", () => {
@@ -24,10 +22,8 @@ describe("PageGenerator", () => {
context: "marketing",
})
it("returns path with context as prefix", async () => {
expect((await generator.getTemplateValues()).modelNamesPath).toBe(
"marketing/projects",
)
it("returns path with context as prefix", () => {
expect(generator.getModelNamesPath()).toEqual("marketing/projects")
})
})
})
@@ -38,7 +34,6 @@ describe("PageGenerator", () => {
expect(values).toEqual({
ModelName: "project",
ModelNames: "projects",
parentModelIdZodType: undefined,
ParentModel: undefined,
ParentModels: undefined,
modelNamesPath: "projects",
@@ -46,7 +41,6 @@ describe("PageGenerator", () => {
modelIdParam: "[projectId]",
modelName: "project",
modelNames: "projects",
modelIdZodType: "number",
parentModel: undefined,
parentModelId: "",
parentModelParam: "",

View File

@@ -2,86 +2,75 @@ import {Schema} from "@mrleebo/prisma-ast"
import {Field} from "../../src/prisma/field"
describe("Field", () => {
process.env.BLITZ_APP_DIR = process.cwd()
it("parses optional types", async () => {
const [field] = await await Field.parse("name:string?")
it("parses optional types", () => {
const [field] = Field.parse("name:string?")
expect(field.isRequired).toBe(false)
})
it("appends unique attribute", async () => {
const [field] = await Field.parse("email:string?:unique")
it("appends unique attribute", () => {
const [field] = Field.parse("email:string?:unique")
expect(field.isUnique).toBe(true)
})
it("appends updatedAt attribute", async () => {
const [field] = await Field.parse("updatedAt:DateTime:updatedAt")
it("appends updatedAt attribute", () => {
const [field] = Field.parse("updatedAt:DateTime:updatedAt")
expect(field.isUpdatedAt).toBe(true)
})
it("handles default simple attribute", async () => {
const [field] = await Field.parse("isActive:boolean:default=true")
it("handles default simple attribute", () => {
const [field] = Field.parse("isActive:boolean:default=true")
expect(field.default).toBe("true")
})
it("handles default uuid attribute", async () => {
const [field] = await Field.parse("id:string:default=uuid")
it("handles default uuid attribute", () => {
const [field] = Field.parse("id:string:default=uuid")
expect(field.default).toMatchObject({name: "uuid"})
})
it("handles uuid convenience syntax", async () => {
const [field] = await Field.parse("someSpecialToken:uuid")
it("handles uuid convenience syntax", () => {
const [field] = Field.parse("someSpecialToken:uuid")
expect(field.type).toBe("String")
expect(field.default).toMatchObject({name: "uuid"})
})
it("handles default autoincrement attribute", async () => {
const [field] = await Field.parse("id:int:default=autoincrement")
it("handles default autoincrement attribute", () => {
const [field] = Field.parse("id:int:default=autoincrement")
expect(field.default).toMatchObject({name: "autoincrement"})
})
it("has default field type", async () => {
const [field] = await Field.parse("name")
it("has default field type", () => {
const [field] = Field.parse("name")
expect(field.type).toBe("String")
})
it("allow number characters in model name", async () => {
const [field] = await Field.parse("name2")
it("allow number characters in model name", () => {
const [field] = Field.parse("name2")
expect(field.name).toBe("name2")
})
it("allow underscore characters in model name", async () => {
const [field] = await Field.parse("first_name")
it("allow underscore characters in model name", () => {
const [field] = Field.parse("first_name")
expect(field.name).toBe("first_name")
})
it("disallows number as a first character in model name", async () => {
await expect(async () => await Field.parse("2first")).rejects.toThrowError(
"[Field.parse]: received unknown special character in field name: 2first",
)
it("disallows number as a first character in model name", () => {
expect(() => Field.parse("2first")).toThrow()
})
it("disallows underscore as a first character in model name", async () => {
await expect(async () => await Field.parse("_first")).rejects.toThrowError(
"[Field.parse]: received unknown special character in field name: _first",
)
it("disallows underscore as a first character in model name", () => {
expect(() => Field.parse("_first")).toThrow()
})
it("disallows special characters in model name", async () => {
await expect(async () => await Field.parse("app-user:int")).rejects.toThrowError(
"[Field.parse]: received unknown special character in field name: app-user",
)
it("disallows special characters in model name", () => {
expect(() => Field.parse("app-user:int")).toThrow()
})
it("disallows optional list fields", async () => {
await expect(async () => await Field.parse("users:int?[]")).rejects.toThrowError(
"[PrismaField]: a type cannot be both optional and a list",
)
it("disallows optional list fields", () => {
expect(() => Field.parse("users:int?[]")).toThrow()
})
it("requires a name", async () => {
await expect(async () => await Field.parse(":int")).rejects.toThrowError(
"[Field.parse]: received unknown special character in field name: ",
)
it("requires a name", () => {
expect(() => Field.parse(":int")).toThrow()
})
describe("belongsTo", () => {
@@ -113,8 +102,8 @@ describe("Field", () => {
],
}
it("simple relation", async () => {
const [relation, foreignKey] = await Field.parse("belongsTo:task")
it("simple relation", () => {
const [relation, foreignKey] = Field.parse("belongsTo:task")
expect(relation).toMatchObject({
name: "task",
type: "Task",
@@ -124,8 +113,8 @@ describe("Field", () => {
expect(foreignKey).toMatchObject({name: "taskId", type: "Int"})
})
it("relation with schema", async () => {
const [relation, foreignKey] = await Field.parse("belongsTo:project?", schema)
it("relation with schema", () => {
const [relation, foreignKey] = Field.parse("belongsTo:project?", schema)
expect(relation).toMatchObject({
name: "project",
type: "Project",
@@ -136,8 +125,8 @@ describe("Field", () => {
expect(foreignKey).toMatchObject({name: "projectId", type: "String", isRequired: false})
})
it("relation with list directive", async () => {
const [relation, foreignKey] = await Field.parse("belongsTo:tasks[]", schema)
it("relation with list directive", () => {
const [relation, foreignKey] = Field.parse("belongsTo:tasks[]", schema)
expect(relation).toMatchObject({name: "tasks", type: "Task", isList: false})
expect(foreignKey).toMatchObject({name: "tasksId", type: "Int", isList: false})
})

View File

@@ -2,16 +2,16 @@ import {Field} from "../../src/prisma/field"
import {Model} from "../../src/prisma/model"
describe("Prisma Model", () => {
it("generates a proper model", async () => {
it("generates a proper model", () => {
expect(
new Model(
"user",
[
await Field.parse("email:string:unique"),
await Field.parse("updated:dateTime:updatedAt"),
await Field.parse("recentLogins:dateTime[]"),
await Field.parse("twoFactorEnabled:boolean"),
await Field.parse("twoFactorMethod:string?"),
Field.parse("email:string:unique"),
Field.parse("updated:dateTime:updatedAt"),
Field.parse("recentLogins:dateTime[]"),
Field.parse("twoFactorEnabled:boolean"),
Field.parse("twoFactorMethod:string?"),
].flat(),
).toString(),
).toMatchSnapshot()

View File

@@ -1,7 +1,7 @@
{
"name": "@blitzjs/server",
"description": "Blitz.js server functionality",
"version": "0.45.2",
"version": "0.45.0-canary.0",
"license": "MIT",
"scripts": {
"test": "jest --passWithNoTests",

View File

@@ -23,7 +23,7 @@
},
"homepage": "https://github.com/blitz-js/blitz#readme",
"dependencies": {
"@blitzjs/installer": "0.45.2",
"@blitzjs/installer": "0.45.0-canary.0",
"jscodeshift": "0.13.0"
},
"devDependencies": {

View File

@@ -22,7 +22,7 @@
},
"homepage": "https://github.com/blitz-js/blitz#readme",
"dependencies": {
"@blitzjs/installer": "0.45.2",
"@blitzjs/installer": "0.45.0-canary.0",
"jscodeshift": "0.13.0"
},
"devDependencies": {

View File

@@ -24,7 +24,7 @@
},
"homepage": "https://github.com/blitz-js/blitz#readme",
"dependencies": {
"@blitzjs/installer": "0.45.2",
"@blitzjs/installer": "0.45.0-canary.0",
"jscodeshift": "0.13.0"
},
"devDependencies": {

View File

@@ -24,7 +24,7 @@
},
"homepage": "https://github.com/blitz-js/blitz#readme",
"dependencies": {
"@blitzjs/installer": "0.45.2",
"@blitzjs/installer": "0.45.0-canary.0",
"jscodeshift": "0.13.0"
},
"devDependencies": {

View File

@@ -22,7 +22,7 @@
},
"homepage": "https://github.com/blitz-js/blitz#readme",
"dependencies": {
"@blitzjs/installer": "0.45.2",
"@blitzjs/installer": "0.45.0-canary.0",
"jscodeshift": "0.13.0"
},
"devDependencies": {

View File

@@ -24,6 +24,6 @@
},
"homepage": "https://github.com/blitz-js/blitz#readme",
"dependencies": {
"@blitzjs/installer": "0.45.2"
"@blitzjs/installer": "0.45.0-canary.0"
}
}

View File

@@ -24,6 +24,6 @@
},
"homepage": "https://github.com/blitz-js/blitz#readme",
"dependencies": {
"@blitzjs/installer": "0.45.2"
"@blitzjs/installer": "0.45.0-canary.0"
}
}

View File

@@ -23,7 +23,7 @@
},
"homepage": "https://github.com/blitz-js/blitz#readme",
"dependencies": {
"@blitzjs/installer": "0.45.2",
"@blitzjs/installer": "0.45.0-canary.0",
"jscodeshift": "0.13.0"
},
"devDependencies": {

View File

@@ -22,7 +22,7 @@
},
"homepage": "https://github.com/blitz-js/blitz#readme",
"dependencies": {
"@blitzjs/installer": "0.45.2",
"@blitzjs/installer": "0.45.0-canary.0",
"jscodeshift": "0.13.0",
"uuid": "^8.3.1"
},

View File

@@ -23,6 +23,6 @@
},
"homepage": "https://github.com/blitz-js/blitz#readme",
"dependencies": {
"@blitzjs/installer": "0.45.2"
"@blitzjs/installer": "0.45.0-canary.0"
}
}

View File

@@ -23,7 +23,7 @@
},
"homepage": "https://github.com/blitz-js/blitz#readme",
"dependencies": {
"@blitzjs/installer": "0.45.2",
"@blitzjs/installer": "0.45.0-canary.0",
"jscodeshift": "0.13.0"
},
"devDependencies": {

View File

@@ -23,6 +23,6 @@
},
"homepage": "https://github.com/blitz-js/blitz#readme",
"dependencies": {
"@blitzjs/installer": "0.45.2"
"@blitzjs/installer": "0.45.0-canary.0"
}
}

View File

@@ -22,6 +22,6 @@
},
"homepage": "https://github.com/blitz-js/blitz#readme",
"dependencies": {
"@blitzjs/installer": "0.45.2"
"@blitzjs/installer": "0.45.0-canary.0"
}
}

View File

@@ -23,7 +23,7 @@
},
"homepage": "https://github.com/blitz-js/blitz#readme",
"dependencies": {
"@blitzjs/installer": "0.45.2",
"@blitzjs/installer": "0.45.0-canary.0",
"jscodeshift": "0.13.0"
},
"devDependencies": {

View File

@@ -22,6 +22,6 @@
},
"homepage": "https://github.com/blitz-js/blitz#readme",
"dependencies": {
"@blitzjs/installer": "0.45.2"
"@blitzjs/installer": "0.45.0-canary.0"
}
}

View File

@@ -22,7 +22,7 @@
},
"homepage": "https://github.com/blitz-js/blitz#readme",
"dependencies": {
"@blitzjs/installer": "0.45.2",
"@blitzjs/installer": "0.45.0-canary.0",
"jscodeshift": "0.13.0",
"uuid": "^8.3.1"
},

View File

@@ -24,7 +24,7 @@
},
"homepage": "https://github.com/blitz-js/blitz#readme",
"dependencies": {
"@blitzjs/installer": "0.45.2",
"@blitzjs/installer": "0.45.0-canary.0",
"jscodeshift": "0.13.0"
},
"devDependencies": {

View File

@@ -24,7 +24,7 @@
},
"homepage": "https://github.com/blitz-js/blitz#readme",
"dependencies": {
"@blitzjs/installer": "0.45.2",
"@blitzjs/installer": "0.45.0-canary.0",
"jscodeshift": "0.13.0"
},
"devDependencies": {

View File

@@ -22,7 +22,7 @@
},
"homepage": "https://github.com/blitz-js/blitz#readme",
"dependencies": {
"@blitzjs/installer": "0.45.2",
"@blitzjs/installer": "0.45.0-canary.0",
"jscodeshift": "0.13.0"
},
"devDependencies": {

View File

@@ -23,7 +23,7 @@
},
"homepage": "https://github.com/blitz-js/blitz#readme",
"dependencies": {
"@blitzjs/installer": "0.45.2",
"@blitzjs/installer": "0.45.0-canary.0",
"jscodeshift": "0.13.0"
},
"devDependencies": {

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