-
Notifications
You must be signed in to change notification settings - Fork 31
POC: codegen from plugin.json #1563
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
hugohaggmark
wants to merge
7
commits into
main
Choose a base branch
from
hugoh-poc-generate-ts-from-plugin-json
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+955
−2
Draft
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
f2c478f
POC: codegen from plugin.json
hugohaggmark 1f46c7e
Merge remote-tracking branch 'origin/main' into hugoh-poc-generate-ts…
hugohaggmark 51dfba3
Merge branch 'main' into hugoh-poc-generate-ts-from-plugin-json
hugohaggmark 171a414
chore: updates schema
hugohaggmark c3a5a7c
chore: updates after PR feedback
hugohaggmark c595f9a
Merge branch 'main' into hugoh-poc-generate-ts-from-plugin-json
hugohaggmark 6f0b870
Merge remote-tracking branch 'origin/main' into hugoh-poc-generate-ts…
hugohaggmark File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
673 changes: 673 additions & 0 deletions
673
packages/create-plugin/templates/common/.config/types/pluginSchema.d.ts
Large diffs are not rendered by default.
Oops, something went wrong.
44 changes: 44 additions & 0 deletions
44
packages/create-plugin/templates/common/.config/webpack/codegen/CodeGenPlugin.ts
This file contains hidden or 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,44 @@ | ||
import type { Compiler } from 'webpack'; | ||
import { watchPluginJson, stopWatchingPluginJson } from './watchPluginJson'; | ||
|
||
/** | ||
* Webpack plugin that watches plugin.json and regenerates TypeScript code | ||
* during development. | ||
*/ | ||
export class CodeGenPlugin { | ||
private watching = false; | ||
|
||
apply(compiler: Compiler) { | ||
// Start watching when webpack enters watch mode | ||
compiler.hooks.watchRun.tap('CodeGenPlugin', () => { | ||
if (this.watching) { | ||
return; | ||
} | ||
|
||
this.watching = true; | ||
watchPluginJson(); | ||
}); | ||
|
||
// Stop watching when webpack exits | ||
compiler.hooks.shutdown.tap('CodeGenPlugin', () => { | ||
this.watching = false; | ||
stopWatchingPluginJson(); | ||
}); | ||
|
||
// Generate code on initial build | ||
compiler.hooks.beforeRun.tapAsync('CodeGenPlugin', async (_, callback) => { | ||
console.log('=========== compiler.hooks.beforeRun ============'); | ||
try { | ||
watchPluginJson(); | ||
callback(); | ||
} catch (error) { | ||
callback(error as Error); | ||
} | ||
}); | ||
|
||
// Prettify after file changes in watch mode | ||
compiler.hooks.afterCompile.tapAsync('CodeGenPlugin', async (_, callback) => { | ||
callback(); | ||
}); | ||
} | ||
} |
61 changes: 61 additions & 0 deletions
61
packages/create-plugin/templates/common/.config/webpack/codegen/generators/pluginIncludes.ts
This file contains hidden or 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,61 @@ | ||
import { CodeGenerator } from '../types'; | ||
import { PluginSchema } from '../../../types/pluginSchema'; | ||
import { FILE_HEADER_COMMENT } from '../utils'; | ||
import { CONFIG_DIR } from '../../constants'; | ||
|
||
function canGenerate(pluginJson: PluginSchema) { | ||
return Boolean(pluginJson?.includes?.length); | ||
} | ||
|
||
function generate(pluginJson: PluginSchema) { | ||
if (!pluginJson?.includes?.length) { | ||
return ''; | ||
} | ||
|
||
// Create dynamic import statement | ||
const imports = 'Include'; | ||
|
||
// Generate includes enum if includes exist | ||
const includesEnum = `export enum PluginIncludePaths { | ||
${pluginJson.includes | ||
.map((inc) => `${inc.name?.replace(/\s+/g, '')} = "${inc.path?.replace(/%PLUGIN_ID%/, pluginJson.id)}"`) | ||
.join(',\n')} | ||
}`; | ||
|
||
// Generate includes map if includes exist | ||
const includesMap = `export const PluginIncludes: ReadonlyMap<PluginIncludePaths, Include> = new Map([ | ||
${pluginJson.includes | ||
.map((inc) => { | ||
const enumKey = inc.name?.replace(/\s+/g, ''); | ||
// Create the include object without JSON.stringify to preserve the enum reference | ||
const include = { | ||
...inc, | ||
path: `PluginIncludePaths.${enumKey}`, | ||
}; | ||
// Convert to string but replace the quoted enum reference with the actual reference | ||
const includeStr = JSON.stringify(include).replace( | ||
`"PluginIncludePaths.${enumKey}"`, | ||
`PluginIncludePaths.${enumKey}` | ||
); | ||
return `[PluginIncludePaths.${enumKey}, ${includeStr}]`; | ||
}) | ||
.join(',\n')} | ||
]);`; | ||
|
||
const fileContent = `${FILE_HEADER_COMMENT} | ||
import { ${imports} } from '../../${CONFIG_DIR}/types/pluginSchema'; | ||
|
||
${includesEnum} | ||
|
||
${includesMap} | ||
`; | ||
|
||
return fileContent; | ||
} | ||
|
||
export const pluginIncludes: CodeGenerator = { | ||
name: 'pluginIncludes', | ||
fileName: 'pluginIncludes.ts', | ||
canGenerate, | ||
generate, | ||
}; |
49 changes: 49 additions & 0 deletions
49
packages/create-plugin/templates/common/.config/webpack/codegen/main.ts
This file contains hidden or 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,49 @@ | ||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; | ||
import path from 'node:path'; | ||
import { FileWriter, FileReader, Prettifier } from './types'; | ||
import { CodeGenerator } from './types'; | ||
import { getPluginJsonPath } from '../utils'; | ||
import { getCodegenDirPath, logError, logInfo, logWarning, prettifyFile } from './utils'; | ||
import { CODEGEN_DIR, SOURCE_DIR } from '../constants'; | ||
import { PluginSchema } from '../../types/pluginSchema'; | ||
import { pluginIncludes } from './generators/pluginIncludes'; | ||
|
||
const codeGenerators: CodeGenerator[] = [pluginIncludes]; | ||
|
||
const fileWriter: FileWriter = (file, content) => { | ||
const outputFile = path.join(process.cwd(), SOURCE_DIR, CODEGEN_DIR, file); | ||
writeFileSync(outputFile, content); | ||
}; | ||
|
||
const fileReader: FileReader = (file) => { | ||
return readFileSync(file, 'utf-8'); | ||
}; | ||
|
||
const prettifier: Prettifier = prettifyFile; | ||
|
||
export function generateCode() { | ||
const pluginJsonPath = getPluginJsonPath(); | ||
const pluginJson: PluginSchema = JSON.parse(fileReader(pluginJsonPath)); | ||
const generators = codeGenerators.filter((generator) => generator.canGenerate(pluginJson)); | ||
if (!generators.length) { | ||
logWarning('No code generators found for plugin.json'); | ||
return; | ||
} | ||
|
||
// Create codegen directory if it doesn't exist | ||
if (!existsSync(getCodegenDirPath())) { | ||
mkdirSync(getCodegenDirPath()); | ||
} | ||
|
||
generators.forEach((generator) => { | ||
try { | ||
logInfo(`Generating code for`, generator.name); | ||
const code = generator.generate(pluginJson); | ||
fileWriter(generator.fileName, code); | ||
prettifier(generator.fileName); | ||
logInfo(`Code generated and prettified for`, generator.name); | ||
} catch (error) { | ||
logError(`Error generating code for ${generator.name}: ${error}`); | ||
} | ||
}); | ||
} |
12 changes: 12 additions & 0 deletions
12
packages/create-plugin/templates/common/.config/webpack/codegen/types.ts
This file contains hidden or 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,12 @@ | ||
import { PluginSchema } from '../../types/pluginSchema'; | ||
|
||
export interface CodeGenerator { | ||
name: string; | ||
fileName: string; | ||
canGenerate: (pluginJson: PluginSchema) => boolean; | ||
generate: (pluginJson: PluginSchema) => string; | ||
} | ||
|
||
export type FileWriter = (file: string, content: string) => void; | ||
export type FileReader = (file: string) => string; | ||
export type Prettifier = (file: string) => void; |
53 changes: 53 additions & 0 deletions
53
packages/create-plugin/templates/common/.config/webpack/codegen/utils.ts
This file contains hidden or 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,53 @@ | ||
import fs from 'fs'; | ||
import { execFile as nodeExecFile } from 'node:child_process'; | ||
import path from 'node:path'; | ||
import { promisify } from 'node:util'; | ||
import { CODEGEN_DIR, CONFIG_DIR, SOURCE_DIR } from '../constants'; | ||
|
||
const execFile = promisify(nodeExecFile); | ||
|
||
export async function prettifyFile(fileName: string) { | ||
try { | ||
const filePath = path.join(process.cwd(), SOURCE_DIR, CODEGEN_DIR, fileName); | ||
if (!fs.existsSync(filePath)) { | ||
return; | ||
} | ||
|
||
const command = 'npx'; | ||
const args = ['prettier', '--write', filePath]; | ||
await execFile(command, args); | ||
} catch (error) { | ||
console.error('Failed to prettify generated file:', error); | ||
} | ||
} | ||
|
||
export const FILE_HEADER_COMMENT = `// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED FROM PLUGIN.JSON`; | ||
|
||
export const colors = { | ||
red: '\x1b[31m', | ||
green: '\x1b[32m', | ||
yellow: '\x1b[33m', | ||
blue: '\x1b[34m', | ||
magenta: '\x1b[35m', | ||
cyan: '\x1b[36m', | ||
reset: '\x1b[0m', | ||
}; | ||
|
||
export function logInfo(message: string, args: string) { | ||
console.log(`codegen --> ${message}${colors.green} ${args}${colors.reset}`); | ||
console.log(''); | ||
} | ||
|
||
export function logWarning(message: string) { | ||
console.log(`codegen --> ${colors.yellow}${message}${colors.reset}`); | ||
console.log(''); | ||
} | ||
|
||
export function logError(message: string) { | ||
console.log(`codegen --> ${colors.red}${message}${colors.reset}`); | ||
console.log(''); | ||
} | ||
|
||
export function getCodegenDirPath() { | ||
return path.join(process.cwd(), SOURCE_DIR, CODEGEN_DIR); | ||
} |
51 changes: 51 additions & 0 deletions
51
packages/create-plugin/templates/common/.config/webpack/codegen/watchPluginJson.ts
This file contains hidden or 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,51 @@ | ||
import { watch, FSWatcher } from 'node:fs'; | ||
import { getPluginJsonPath } from '../utils'; | ||
import { generateCode } from './main'; | ||
import { colors } from './utils'; | ||
|
||
let watcher: FSWatcher | null = null; | ||
const start = `${colors.green}============================================ <CodeGenPlugin> ============================================${colors.reset}`; | ||
const end = `${colors.green}============================================ </CodeGenPlugin> ============================================${colors.reset}`; | ||
/** | ||
* Watches the plugin.json file and regenerates TypeScript types when it changes | ||
*/ | ||
export function watchPluginJson() { | ||
const pluginJsonPath = getPluginJsonPath(); | ||
|
||
// Clean up existing watcher if any | ||
stopWatchingPluginJson(); | ||
|
||
// Generate initial values | ||
try { | ||
console.log(start); | ||
console.log(''); | ||
generateCode(); | ||
console.log(end); | ||
console.log(''); | ||
} catch (error) { | ||
console.error('Failed to generate plugin types:', error); | ||
} | ||
|
||
// Start watching for changes | ||
watcher = watch(pluginJsonPath, async (eventType) => { | ||
if (eventType === 'change') { | ||
console.log(start); | ||
console.log(''); | ||
generateCode(); | ||
console.log(end); | ||
console.log(''); | ||
} | ||
}); | ||
|
||
return watcher; | ||
} | ||
|
||
/** | ||
* Stop watching plugin.json file | ||
*/ | ||
export function stopWatchingPluginJson() { | ||
if (watcher) { | ||
watcher.close(); | ||
watcher = null; | ||
} | ||
} |
2 changes: 2 additions & 0 deletions
2
packages/create-plugin/templates/common/.config/webpack/constants.ts
This file contains hidden or 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 |
---|---|---|
@@ -1,2 +1,4 @@ | ||
export const SOURCE_DIR = 'src'; | ||
export const DIST_DIR = 'dist'; | ||
export const CODEGEN_DIR = 'codegen'; | ||
export const CONFIG_DIR = '.config'; |
This file contains hidden or 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 hidden or 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 hidden or 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 |
---|---|---|
|
@@ -44,3 +44,6 @@ ci/ | |
.idea | ||
|
||
.eslintcache | ||
|
||
# Code generated by create-plugin | ||
/codegen |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.