-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(scaffold): update VE template generation (#563)
Realigns the VE template generation output against the latest changes we've made in the starter. This includes updating the main.tsx template, adding the theme.config.ts, adding utils/buildSchema.ts, updating tailwind.config.ts to use the themeConfig, and adding to .template-manifest.json. Even though this updates the command, it also removes the VE template generation option until hybrid mode is better supported.
- Loading branch information
1 parent
4fe7b8e
commit 79a3d6b
Showing
8 changed files
with
806 additions
and
103 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
47 changes: 47 additions & 0 deletions
47
packages/pages/src/common/src/parsers/tailwindConfigParser.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { describe, it, expect } from "vitest"; | ||
import fs from "node:fs"; | ||
import { | ||
addThemeConfigToTailwind, | ||
tailwindConfigFilename, | ||
} from "./tailwindConfigParser.js"; | ||
|
||
describe("addDataToPuckConfig", () => { | ||
it("should throw an error if the filepath is invalid", () => { | ||
expect(() => addThemeConfigToTailwind("invalid/filepath")).toThrow( | ||
'Filepath "invalid/filepath" is invalid.' | ||
); | ||
}); | ||
|
||
it("correctly adds the theme config to the tailwind config", () => { | ||
try { | ||
fs.writeFileSync( | ||
tailwindConfigFilename, | ||
`import type { Config } from "tailwindcss"; | ||
export default { | ||
content: [ | ||
"./src/**/*.{html,js,jsx,ts,tsx}", | ||
"./node_modules/@yext/visual-editor/dist/**/*.js", | ||
], | ||
plugins: [], | ||
} satisfies Config; | ||
` | ||
); | ||
addThemeConfigToTailwind(tailwindConfigFilename); | ||
const modifiedContent = fs.readFileSync(tailwindConfigFilename, "utf-8"); | ||
expect(modifiedContent).toContain(`theme: { | ||
extend: themeResolver({}, themeConfig) | ||
}`); | ||
expect(modifiedContent).toContain( | ||
`import { themeConfig } from "./theme.config";` | ||
); | ||
expect(modifiedContent).toContain( | ||
`import { themeResolver } from "@yext/visual-editor";` | ||
); | ||
} finally { | ||
if (fs.existsSync(tailwindConfigFilename)) { | ||
fs.unlinkSync(tailwindConfigFilename); | ||
} | ||
} | ||
}); | ||
}); |
117 changes: 117 additions & 0 deletions
117
packages/pages/src/common/src/parsers/tailwindConfigParser.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import fs from "node:fs"; | ||
import SourceFileParser, { createTsMorphProject } from "./sourceFileParser.js"; | ||
import { | ||
ObjectLiteralExpression, | ||
PropertyAssignment, | ||
SyntaxKind, | ||
} from "ts-morph"; | ||
|
||
export const tailwindConfigFilename = "tailwind.config.ts"; | ||
|
||
/** | ||
* Adds the themeConfig to tailwind.config.ts if it's not there. | ||
*/ | ||
export const addThemeConfigToTailwind = (tailwindConfigPath: string) => { | ||
if (!fs.existsSync(tailwindConfigPath)) { | ||
throw new Error(`Filepath "${tailwindConfigPath}" is invalid.`); | ||
} | ||
|
||
const parser = new SourceFileParser( | ||
tailwindConfigPath, | ||
createTsMorphProject() | ||
); | ||
|
||
const defaultExport = parser | ||
.getSourceFile() | ||
.getFirstDescendantByKind(SyntaxKind.ExportAssignment); | ||
|
||
if (!defaultExport) { | ||
throw new Error("Default export not found in the file."); | ||
} | ||
|
||
// Get the initializer of the default export | ||
const exportInitializer = defaultExport.getExpression(); | ||
|
||
if (!exportInitializer) { | ||
throw new Error("No initializer found for the default export."); | ||
} | ||
|
||
// If the initializer includes a `satisfies` clause, extract the object literal | ||
let configObject: ObjectLiteralExpression | undefined; | ||
if ( | ||
exportInitializer.getKind() === SyntaxKind.AsExpression || | ||
exportInitializer.getKind() === SyntaxKind.SatisfiesExpression | ||
) { | ||
const innerExpression = exportInitializer.getChildAtIndex(0); // Extract left-hand side | ||
if (innerExpression.getKind() === SyntaxKind.ObjectLiteralExpression) { | ||
configObject = innerExpression.asKind(SyntaxKind.ObjectLiteralExpression); | ||
} | ||
} else if ( | ||
exportInitializer.getKind() === SyntaxKind.ObjectLiteralExpression | ||
) { | ||
configObject = exportInitializer.asKind(SyntaxKind.ObjectLiteralExpression); | ||
} | ||
|
||
if (!configObject) { | ||
throw new Error("Config object not found in the default export."); | ||
} | ||
|
||
// Locate the "theme" property | ||
let themeProperty = configObject.getProperty("theme") as PropertyAssignment; | ||
|
||
if ( | ||
!themeProperty || | ||
themeProperty.getKind() !== SyntaxKind.PropertyAssignment | ||
) { | ||
// Add the "theme" property if it doesn't exist | ||
themeProperty = configObject.addPropertyAssignment({ | ||
name: "theme", | ||
initializer: `{ | ||
extend: themeResolver({}, themeConfig) | ||
}`, | ||
}); | ||
} | ||
|
||
// Get the value of the theme property | ||
const themeValue = (themeProperty as PropertyAssignment).getInitializer(); | ||
|
||
if (!themeValue) { | ||
throw new Error("Unable to determine theme initializer."); | ||
} | ||
|
||
// Check if the theme value is a function call or object literal | ||
if (themeValue.getKind() === SyntaxKind.CallExpression) { | ||
// The theme is resolved using a function call | ||
(themeProperty as PropertyAssignment).setInitializer(`{ | ||
extend: themeResolver({}, themeConfig) | ||
}`); | ||
} else if (themeValue.getKind() === SyntaxKind.ObjectLiteralExpression) { | ||
// The theme is a regular object literal | ||
const extendProperty = (themeValue as ObjectLiteralExpression).getProperty( | ||
"extend" | ||
); | ||
if ( | ||
extendProperty && | ||
extendProperty.getKind() === SyntaxKind.PropertyAssignment | ||
) { | ||
// Modify or replace the "extend" property | ||
(extendProperty as PropertyAssignment).setInitializer( | ||
`themeResolver({}, themeConfig)` | ||
); | ||
} else { | ||
// Add "extend" if it doesn't exist | ||
(themeValue as ObjectLiteralExpression).addPropertyAssignment({ | ||
name: "extend", | ||
initializer: `themeResolver({}, themeConfig)`, | ||
}); | ||
} | ||
} else { | ||
throw new Error("Unsupported initializer type for the theme property."); | ||
} | ||
|
||
parser.ensureNamedImport("./theme.config", "themeConfig"); | ||
parser.ensureNamedImport("@yext/visual-editor", "themeResolver"); | ||
|
||
parser.format(); | ||
parser.save(); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.