This is Gradle plugin for Enonic XP 7 projects. It requires at least Gradle 7.3.1.
The plugin parses the Enonic projects XML-files, and generates TypeScript interfaces that can be used in your server- or client-side code.
This creates a tight coupling between your configuration and your code. If you change an xml-file, the TypeScript -files will be regenerated, and it will not compile until you have fixed your code.
This plugin can create interfaces for:
- Content types
- Pages
- Parts
- Site
- Layout
- Tasks
- Macros
- Id-provider
- Mixins
- X-data
To get started add the following to your project's build.gradle file:
plugins {
id 'java'
id 'no.item.xp.codegen' version '2.3.0'
}
jar {
// Add this before your TypeScript build task
dependsOn += generateTypeScript
}
// Add dependency to webpack tasks too
task serverWebpack( type: NodeTask, dependsOn: [ npmInstall, generateTypeScript ] ) {
...
}
By setting the rootDirs
field in tsconfig.json, you can "overlay" the two directory structures over each other, and
references to generated Types becomes very natural.
E.g if you have a content type in "./resources/site/content-types/article/article.xml", the generated TypeScript interface for that type can be imported from "./resources/site/content-types/article" (or alternatively from "./resources/site/content-types").
{
"compilerOptions": {
...
"rootDirs": [
"./src/main/resources",
"./.xp-codegen"
]
},
"include": [
"./.xp-codegen/**/*",
"./src/main/resources/**/*"
]
}
Here is an example of how an xml-file can be parsed to create a TypeScript interface.
We have created a content type for Article
in the file content-types/article/article.xml:
<?xml version="1.0" encoding="UTF-8"?>
<content-type>
<display-name>Article</display-name>
<super-type>base:structured</super-type>
<form>
<input name="title" type="TextLine">
<label>Title of the article</label>
<occurrences minimum="1" maximum="1"/>
</input>
<input name="body" type="HtmlArea">
<label>Main text body</label>
<occurrences minimum="0" maximum="1"/>
</input>
</form>
</content-type>
We can then run the ./gradlew generateTypeScript
task, which will generate a new file in
content-types/article/article.ts with the following content:
// WARNING: This file was automatically generated by "no.item.xp.codegen". You may lose your changes if you edit it.
export interface Article {
/**
* Title of the article
*/
title: string;
/**
* Main text body
*/
body?: string;
/**
* GraphQL name. Also used for separating unions in TypeScript
*/
__typename?: "com_mysite_Article_Data";
}
The following configuration options can be used:
- singleQuote (
boolean
) – Iftrue
all"
in output will be replaced with'
. - prependText (
string
) – Code to prepend to all the generated code files. By default this is the WARNING-text.
jar {
dependsOn += generateTypeScript {
singleQuote = true
prependText = "// This is a different message"
}
}
Note You can use
prependText
to give instructions to the e.g. the linter. If you add/* eslint-disable prettier/prettier */
you can stop eslint from processing the generated files.
Here we can see an example of using generated interfaces it in a part specified in "./site/parts/article-view/article-view.xml".
// We can import the generated Article interface from "./site/content-types/index.d.ts"
import type { Article } from "../../content-types";
// We can import the shape of the part config from "./index.d.ts"
import type { ArticleView } from ".";
// imports from XP libraries:
import { getContent, getComponent } from "/lib/xp/portal";
import { render } from "/lib/thymeleaf";
const view = resolve("article-view.html");
export function get(): XP.Response {
const content = getContent<Article>();
const part = getComponent<ArticleView>();
return {
status: 200,
body: render<ThymeleafParams>(view, {
title: content.displayName,
preface: content.data.preface,
backgroundColor: part.config.backgroundColor
}),
};
}
interface ThymeleafParams {
title: string;
preface: string | undefined;
backgroundColor: string;
}
To test this plugin locally you can run the following task to publish the plugin locally on your machine.
./gradlew publishToMavenLocal
Then – in your Enonic-project – you can add the following to the top of your settings.gradle file to use the plugin:
pluginManagement {
repositories {
mavenLocal()
gradlePluginPortal()
}
}
To use the plugin your can just run the following task:
./gradlew generateTypeScript
To run the unit tests, linting and plugin verification in the project you can run:
./gradlew test
./gradlew ktlintFormat
./gradlew validatePlugins
You should always run ./gradlew ktlintFormat
before committing code to git!
To publish to the plugin portal, you first need to set up your local api-keys. Instrunctions can be found in the plugin documentation.
Then you can run the following to submit the plugin to the plugin portal:
./gradlew publishPlugins