Skip to content

Commit

Permalink
Unify recipes Program types and fix blitz install (#2952)
Browse files Browse the repository at this point in the history
(patch)
  • Loading branch information
JuanM04 authored Nov 14, 2021
1 parent 18c6981 commit ee07fc3
Show file tree
Hide file tree
Showing 23 changed files with 81 additions and 83 deletions.
7 changes: 3 additions & 4 deletions packages/generator/src/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import Enquirer from "enquirer"
import {EventEmitter} from "events"
import * as fs from "fs-extra"
import j from "jscodeshift"
import {Collection} from "jscodeshift/src/Collection"
import {create as createStore, Store} from "mem-fs"
import {create as createEditor, Editor} from "mem-fs-editor"
import * as path from "path"
Expand Down Expand Up @@ -70,9 +69,9 @@ function replaceConditionalNode(
// expressions that aren't targeting templateValues so templates can include
// checks for other env variables
function replaceConditionalStatements(
program: Collection<j.Program>,
program: j.Collection<j.Program>,
templateValues: any,
): Collection<j.Program> {
): j.Collection<j.Program> {
const processEnvRequirements = {
test: {
object: {
Expand All @@ -90,7 +89,7 @@ function replaceConditionalStatements(
return program
}

function replaceJsxConditionals(program: Collection<j.Program>, templateValues: any) {
function replaceJsxConditionals(program: j.Collection<j.Program>, templateValues: any) {
program.find(j.JSXIdentifier, {name: "if"}).forEach((path) => {
if (j.JSXOpeningElement.check(path.parent.node)) {
const conditionPath = j(path.parent)
Expand Down
1 change: 1 addition & 0 deletions packages/installer/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ export {type as PrintMessageType} from "./executors/print-message-executor"
export * from "./utils/paths"
export * from "./transforms"
export {customTsParser} from "./utils/transform"
export type {Program} from "./types"
3 changes: 2 additions & 1 deletion packages/installer/src/transforms/add-blitz-middleware.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import type {ExpressionKind} from "ast-types/gen/kinds"
import j from "jscodeshift"
import {Program} from "../types"
import {transformBlitzConfig} from "."

export const addBlitzMiddleware = (program: j.Collection<j.Program>, middleware: ExpressionKind) =>
export const addBlitzMiddleware = (program: Program, middleware: ExpressionKind): Program =>
transformBlitzConfig(program, (config) => {
// Locate the middleware property
const middlewareProp = config.properties.find(
Expand Down
7 changes: 2 additions & 5 deletions packages/installer/src/transforms/add-import.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import j from "jscodeshift"
import {Collection} from "jscodeshift/src/Collection"
import {Program} from "../types"

export function addImport(
program: Collection<j.Program>,
importToAdd: j.ImportDeclaration,
): Collection<j.Program> {
export function addImport(program: Program, importToAdd: j.ImportDeclaration): Program {
const importStatementCount = program.find(j.ImportDeclaration).length
if (importStatementCount === 0) {
program.find(j.Statement).at(0).insertBefore(importToAdd)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import j from "jscodeshift"
import {Collection} from "jscodeshift/src/Collection"
import {Program} from "../types"

export function findModuleExportsExpressions(program: Collection<j.Program>) {
return program.find(j.AssignmentExpression).filter((path) => {
export const findModuleExportsExpressions = (program: Program) =>
program.find(j.AssignmentExpression).filter((path) => {
const {left, right} = path.value
return (
left.type === "MemberExpression" &&
Expand All @@ -12,4 +12,3 @@ export function findModuleExportsExpressions(program: Collection<j.Program>) {
right.type === "ObjectExpression"
)
})
}
7 changes: 4 additions & 3 deletions packages/installer/src/transforms/transform-blitz-config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import type {ExpressionKind} from "ast-types/gen/kinds"
import j from "jscodeshift"
import {Program} from "../types"

function recursiveConfigSearch(
program: j.Collection<j.Program>,
program: Program,
obj: ExpressionKind,
): j.ObjectExpression | undefined {
// Identifier being a variable name
Expand Down Expand Up @@ -41,9 +42,9 @@ function recursiveConfigSearch(
export type TransformBlitzConfigCallback = (config: j.ObjectExpression) => j.ObjectExpression

export function transformBlitzConfig(
program: j.Collection<j.Program>,
program: Program,
transform: TransformBlitzConfigCallback,
): j.Collection<j.Program> {
): Program {
let moduleExportsExpressions = program.find(j.AssignmentExpression, {
operator: "=",
left: {object: {name: "module"}, property: {name: "exports"}},
Expand Down
11 changes: 4 additions & 7 deletions packages/installer/src/transforms/update-babel-config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type {ExpressionKind} from "ast-types/gen/kinds"
import j from "jscodeshift"
import {JsonObject, JsonValue} from "../types"
import {Program} from "../types"
import {findModuleExportsExpressions} from "./find-module-exports-expressions"

type AddBabelItemDefinition = string | [name: string, options: JsonObject]
Expand All @@ -24,11 +25,7 @@ const jsonValueToExpression = (value: JsonValue): ExpressionKind =>
),
)

function updateBabelConfig(
program: j.Collection<j.Program>,
item: AddBabelItemDefinition,
key: string,
) {
function updateBabelConfig(program: Program, item: AddBabelItemDefinition, key: string): Program {
findModuleExportsExpressions(program).forEach((moduleExportsExpression) => {
j(moduleExportsExpression)
.find(j.ObjectProperty, {key: {name: key}})
Expand Down Expand Up @@ -108,7 +105,7 @@ function updateBabelConfig(
return program
}

export const addBabelPreset = (program: j.Collection<j.Program>, preset: AddBabelItemDefinition) =>
export const addBabelPreset = (program: Program, preset: AddBabelItemDefinition): Program =>
updateBabelConfig(program, preset, "presets")
export const addBabelPlugin = (program: j.Collection<j.Program>, plugin: AddBabelItemDefinition) =>
export const addBabelPlugin = (program: Program, plugin: AddBabelItemDefinition): Program =>
updateBabelConfig(program, plugin, "plugins")
7 changes: 2 additions & 5 deletions packages/installer/src/transforms/wrap-blitz-config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import j from "jscodeshift"
import {Collection} from "jscodeshift/src/Collection"
import {Program} from "../types"

export function wrapBlitzConfig(
program: Collection<j.Program>,
functionName: string,
): Collection<j.Program> {
export function wrapBlitzConfig(program: Program, functionName: string): Program {
let moduleExportsExpressions = program.find(j.AssignmentExpression, {
operator: "=",
left: {object: {name: "module"}, property: {name: "exports"}},
Expand Down
4 changes: 4 additions & 0 deletions packages/installer/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import type * as j from "jscodeshift"

export interface RecipeMeta {
name: string
description: string
owner: string
repoLink: string
}

export type Program = j.Collection<j.Program>

/**
Matches a JSON object.
This type can be useful to enforce some input to be JSON-compatible or as a super-type to be extended from. Don't use this as a direct return type as the user would have to double-cast it: `jsonObject as unknown as CustomResponse`. Instead, you could extend your CustomResponse type from it to ensure your type only uses JSON-compatible types: `interface CustomResponse extends JsonObject { … }`.
Expand Down
6 changes: 2 additions & 4 deletions packages/installer/src/utils/transform.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as fs from "fs-extra"
import j from "jscodeshift"
import {Collection} from "jscodeshift/src/Collection"
import getBabelOptions, {Overrides} from "recast/parsers/_babel_options"
import * as babel from "recast/parsers/babel"
import {Program} from "../types"

export const customTsParser = {
parse(source: string, options?: Overrides) {
Expand All @@ -24,9 +24,7 @@ export interface TransformResult {
}

export type StringTransformer = (program: string) => string | Promise<string>
export type Transformer = (
program: Collection<j.Program>,
) => Collection<j.Program> | Promise<Collection<j.Program>>
export type Transformer = (program: Program) => Program | Promise<Program>

export function stringProcessFile(
original: string,
Expand Down
4 changes: 2 additions & 2 deletions recipes/base-web/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default RecipeBuilder()
stepName: "Import required providers and wrap the root of the app with them",
explanation: `Additionally we supply StyletronProvider with 'value' and 'debug' props. BaseProvider requires a 'theme' prop we set with default Base Web's light theme.`,
singleFileSearch: paths.app(),
transform(program: j.Collection<j.Program>) {
transform(program) {
const styletronProviderImport = j.importDeclaration(
[j.importSpecifier(j.identifier("Provider"), j.identifier("StyletronProvider"))],
j.literal("styletron-react"),
Expand Down Expand Up @@ -102,7 +102,7 @@ export default RecipeBuilder()
stepName: "Modify getInitialProps method and add stylesheets to Document",
explanation: `To make Styletron work server-side we need to modify getInitialProps method of custom Document class. We also have to put Styletron's generated stylesheets in DocumentHead.`,
singleFileSearch: paths.document(),
transform(program: j.Collection<j.Program>) {
transform(program) {
const styletronProviderImport = j.importDeclaration(
[j.importSpecifier(j.identifier("Provider"), j.identifier("StyletronProvider"))],
j.literal("styletron-react"),
Expand Down
2 changes: 1 addition & 1 deletion recipes/bulma/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default RecipeBuilder()
stepName: "Import stylesheets",
explanation: `Imports the stylesheet we just added into your app`,
singleFileSearch: paths.app(),
transform(program: j.Collection<j.Program>) {
transform(program) {
const stylesImport = j.importDeclaration([], j.literal("app/core/styles/index.scss"))
return addImport(program, stylesImport)
},
Expand Down
10 changes: 5 additions & 5 deletions recipes/bumbag-ui/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {addImport, paths, RecipeBuilder} from "@blitzjs/installer"
import {addImport, paths, Program, RecipeBuilder} from "@blitzjs/installer"
import type {NodePath} from "ast-types/lib/node-path"
import j from "jscodeshift"

function wrapComponentWithBumbagProvider(program: j.Collection<j.Program>) {
function wrapComponentWithBumbagProvider(program: Program) {
program
.find(j.JSXElement)
.filter(
Expand All @@ -27,7 +27,7 @@ function wrapComponentWithBumbagProvider(program: j.Collection<j.Program>) {
return program
}

function injectInitializeColorModeAndExtractCritical(program: j.Collection<j.Program>) {
function injectInitializeColorModeAndExtractCritical(program: Program) {
// Finds body element and injects InitializeColorMode before it.
program.find(j.JSXElement, {openingElement: {name: {name: "body"}}}).forEach((path) => {
const {node} = path
Expand Down Expand Up @@ -88,7 +88,7 @@ export default RecipeBuilder()
stepName: "Import BumbagProvider",
explanation: `Import bumbag Provider as BumbagProvider into _app`,
singleFileSearch: paths.app(),
transform(program: j.Collection<j.Program>) {
transform(program) {
const stylesImport = j.importDeclaration(
[j.importSpecifier(j.identifier("Provider as BumbagProvider"))],
j.literal("bumbag"),
Expand All @@ -103,7 +103,7 @@ export default RecipeBuilder()
stepName: "ImportExtractCritical & initializeColorMode",
explanation: `Import InitializeColorMode from bumbag, and extractCritical into _document`,
singleFileSearch: paths.document(),
transform(program: j.Collection<j.Program>) {
transform(program) {
const initializeColorModeImport = j.importDeclaration(
[j.importSpecifier(j.identifier("InitializeColorMode"))],
j.literal("bumbag"),
Expand Down
18 changes: 9 additions & 9 deletions recipes/chakra-ui/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {addImport, paths, RecipeBuilder} from "@blitzjs/installer"
import {addImport, paths, Program, RecipeBuilder} from "@blitzjs/installer"
import type {NodePath} from "ast-types/lib/node-path"
import j, {JSXIdentifier} from "jscodeshift"

// Copied from https://github.com/blitz-js/blitz/pull/805, let's add this to the @blitzjs/installer
function wrapComponentWithChakraProvider(program: j.Collection<j.Program>) {
function wrapComponentWithChakraProvider(program: Program) {
program
.find(j.JSXElement)
.filter(
Expand All @@ -24,7 +24,7 @@ function wrapComponentWithChakraProvider(program: j.Collection<j.Program>) {
return program
}

function updateLabeledTextFieldWithInputComponent(program: j.Collection<j.Program>) {
function updateLabeledTextFieldWithInputComponent(program: Program) {
program
.find(j.TSInterfaceDeclaration)
.find(j.TSExpressionWithTypeArguments)
Expand All @@ -40,7 +40,7 @@ function updateLabeledTextFieldWithInputComponent(program: j.Collection<j.Progra
return program
}

function replaceOuterDivWithFormControl(program: j.Collection<j.Program>) {
function replaceOuterDivWithFormControl(program: Program) {
program
.find(j.JSXElement)
.filter((path) => {
Expand Down Expand Up @@ -68,7 +68,7 @@ function replaceOuterDivWithFormControl(program: j.Collection<j.Program>) {
return program
}

function replaceInputWithChakraInput(program: j.Collection<j.Program>) {
function replaceInputWithChakraInput(program: Program) {
program
.find(j.JSXElement)
.filter((path) => {
Expand All @@ -89,7 +89,7 @@ function replaceInputWithChakraInput(program: j.Collection<j.Program>) {
return program
}

function replaceLabelWithChakraLabel(program: j.Collection<j.Program>) {
function replaceLabelWithChakraLabel(program: Program) {
program
.find(j.JSXElement)
.filter((path) => {
Expand All @@ -109,7 +109,7 @@ function replaceLabelWithChakraLabel(program: j.Collection<j.Program>) {
return program
}

function removeDefaultStyleElement(program: j.Collection<j.Program>) {
function removeDefaultStyleElement(program: Program) {
program
.find(j.JSXElement)
.filter((path) => {
Expand Down Expand Up @@ -148,7 +148,7 @@ export default RecipeBuilder()
stepName: "Import ChakraProvider component",
explanation: `Import the chakra-ui provider into _app, so it is accessible in the whole app`,
singleFileSearch: paths.app(),
transform(program: j.Collection<j.Program>) {
transform(program) {
const stylesImport = j.importDeclaration(
[j.importSpecifier(j.identifier("ChakraProvider"))],
j.literal("@chakra-ui/react"),
Expand All @@ -163,7 +163,7 @@ export default RecipeBuilder()
stepName: "Update the `LabeledTextField` with Chakra UI's `Input` component",
explanation: `The LabeledTextField component uses Chakra UI's input component`,
singleFileSearch: "app/core/components/LabeledTextField.tsx",
transform(program: j.Collection<j.Program>) {
transform(program) {
// Add ComponentPropsWithoutRef import
program.find(j.ImportDeclaration, {source: {value: "react"}}).forEach((path) => {
let specifiers = path.value.specifiers || []
Expand Down
15 changes: 11 additions & 4 deletions recipes/emotion/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import {addBabelPlugin, addBabelPreset, addImport, paths, RecipeBuilder} from "@blitzjs/installer"
import {
addBabelPlugin,
addBabelPreset,
addImport,
paths,
Program,
RecipeBuilder,
} from "@blitzjs/installer"
import j from "jscodeshift"
import {join} from "path"

function applyGlobalStyles(program: j.Collection<j.Program>) {
function applyGlobalStyles(program: Program) {
program.find(j.ExportDefaultDeclaration).forEach((exportPath) => {
j(exportPath)
.find(j.JSXElement, {openingElement: {name: {name: "ErrorBoundary"}}})
Expand Down Expand Up @@ -49,7 +56,7 @@ export default RecipeBuilder()
stepName: "Import global styles",
explanation: `Next, we'll import and render the global styles.`,
singleFileSearch: paths.app(),
transform(program: j.Collection<j.Program>) {
transform(program) {
const stylesImport = j.importDeclaration(
[j.importSpecifier(j.identifier("globalStyles"))],
j.literal("app/core/styles"),
Expand All @@ -64,7 +71,7 @@ export default RecipeBuilder()
stepName: "Add Babel plugin and preset",
explanation: `Update the Babel configuration to use Emotion's plugin and preset to enable some advanced features.`,
singleFileSearch: paths.babelConfig(),
transform(program: j.Collection<j.Program>) {
transform(program) {
program = addBabelPlugin(program, "@emotion")
program = addBabelPreset(program, [
"preset-react",
Expand Down
3 changes: 1 addition & 2 deletions recipes/ghost/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {addBlitzMiddleware, addImport, paths, RecipeBuilder} from "@blitzjs/installer"
import j from "jscodeshift"
import {Collection} from "jscodeshift"
import path from "path"

export default RecipeBuilder()
Expand Down Expand Up @@ -54,7 +53,7 @@ export default RecipeBuilder()
stepName: "Add default middleware to expose ghost",
explanation: "Adds ghostapi to middleware so we can expose it in queries and mutations.",
singleFileSearch: paths.blitzConfig(),
transform(program: j.Collection<j.Program>) {
transform(program) {
// // import ghostApi from integrations/ghost
const cssBaselineImport = j.importDeclaration(
[j.importSpecifier(j.identifier("ghostApi"))],
Expand Down
2 changes: 1 addition & 1 deletion recipes/logrocket/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default RecipeBuilder()
stepName: "Import helpers and log user upon login",
explanation: `We will add logic to initialize the LogRocket session and upon login, identify the user within LogRocket`,
singleFileSearch: paths.app(),
transform(program: j.Collection<j.Program>) {
transform(program) {
// Ensure useSession is in the blitz imports.
program.find(j.ImportDeclaration, {source: {value: "blitz"}}).forEach((blitzImportPath) => {
let specifiers = blitzImportPath.value.specifiers || []
Expand Down
2 changes: 1 addition & 1 deletion recipes/material-ui/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ This will let the next.js app opt out of the React.Strict mode wrapping. Once yo
stepName: "Add custom getInitialProps logic in Custom Document",
explanation: `We will add custom getInitialProps logic in _document. We need to do this so that styles are correctly rendered on the server side.`,
singleFileSearch: paths.document(),
transform(program: j.Collection<j.Program>) {
transform(program) {
// import ServerStyleSheets
const serverStyleSheetsImport = j.importDeclaration(
[j.importSpecifier(j.identifier("ServerStyleSheets"))],
Expand Down
Loading

0 comments on commit ee07fc3

Please sign in to comment.