diff --git a/package.json b/package.json index 3f2654a319..4d957dea86 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "scripts": { "clean:build": "nx run-many -t clean:build --all --output-style stream", "check": "nx run-many -t lint,typecheck --all --output-style stream", - "build": "sh ./scripts/prepare.sh && nx run-many -t build --all --output-style stream", + "build": "tsx scripts/prepare/index.ts && nx run-many -t build --all --output-style stream", "build:nocache": "npm run build", "lint": "nx run-many -t lint --all --output-style stream", "lint:fix": "nx run-many -t lint:fix --all --output-style stream", diff --git a/scripts/generator/generate.js b/scripts/generator/generate.js deleted file mode 100644 index f34c222f2c..0000000000 --- a/scripts/generator/generate.js +++ /dev/null @@ -1,55 +0,0 @@ -const path = require('path'); -const fs = require('fs'); - -const writer = require('./src/writer'); -const transformer = require('./src/transformer'); - -const hillaVersion = process.argv[2]; -const versionsFileName = process.argv[3]; -const resultsDir = path.resolve(`${__dirname}/results`); - -const inputVersions = JSON.parse(fs.readFileSync(versionsFileName)); - -function getTemplateFilePath(filename) { - return path.resolve(`${__dirname}/templates/${filename}`); -} - -function getResultsFilePath(filename) { - return path.resolve(`${__dirname}/results/${filename}`); -} - -const hillaJsonTemplateFileName = getTemplateFilePath('template-hilla-versions.json'); -const hillaJsonResultFileName = getResultsFilePath('hilla-versions.json'); - -const hillaReactJsonTemplateFileName = getTemplateFilePath('template-hilla-react-versions.json'); -const hillaReactJsonResultFileName = getResultsFilePath('hilla-react-versions.json'); - -const versions = transformer.transformVersions(inputVersions, hillaVersion, false); -versions.platform = hillaVersion; - -if (!fs.existsSync(resultsDir)) { - fs.mkdirSync(resultsDir); -} - -const releaseNotesTemplateFileName = getTemplateFilePath('template-release-note.md'); -const releaseNotesResultFileName = getResultsFilePath('release-note.md'); -const releaseNotesMaintenanceTemplateFileName = getTemplateFilePath('template-release-note-maintenance.md'); -const releaseNotesMaintenanceResultFileName = getResultsFilePath('release-note-maintenance.md'); -const releaseNotesPrereleaseTemplateFileName = getTemplateFilePath('template-release-note-prerelease.md'); -const releaseNotesPrereleaseResultFileName = getResultsFilePath('release-note-prerelease.md'); - -writer.writeSeparateJson(versions.bundles, hillaJsonTemplateFileName, hillaJsonResultFileName, "bundles"); -writer.writeSeparateJson(versions.core, hillaJsonTemplateFileName, hillaJsonResultFileName, "core"); -writer.writeSeparateJson(versions.vaadin, hillaJsonTemplateFileName, hillaJsonResultFileName, "vaadin"); -writer.writeSeparateJson(versions.bundles, hillaReactJsonTemplateFileName, hillaReactJsonResultFileName, "bundles"); -writer.writeSeparateJson(versions.react, hillaReactJsonTemplateFileName, hillaReactJsonResultFileName, "react"); - -writer.writeReleaseNotes(versions, releaseNotesTemplateFileName, releaseNotesResultFileName); -writer.writeReleaseNotes(versions, releaseNotesMaintenanceTemplateFileName, releaseNotesMaintenanceResultFileName); -writer.writeReleaseNotes(versions, releaseNotesPrereleaseTemplateFileName, releaseNotesPrereleaseResultFileName); - -versions.core.hilla = {javaVersion: hillaVersion}; -// write hilla version to hilla-react-versions.json as platform -const hillaVersions = {platform : hillaVersion}; -writer.writeSeparateJson(hillaVersions.platform, hillaJsonTemplateFileName, hillaJsonResultFileName, "platform"); -writer.writeSeparateJson(hillaVersions.platform, hillaReactJsonTemplateFileName, hillaReactJsonResultFileName, "platform"); diff --git a/scripts/generator/package.json b/scripts/generator/package.json deleted file mode 100644 index 623456ba5c..0000000000 --- a/scripts/generator/package.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "name": "generator" -} diff --git a/scripts/prepare.sh b/scripts/prepare.sh deleted file mode 100755 index 6d95e52338..0000000000 --- a/scripts/prepare.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env bash - -# use hilla version from the root hilla npm modules package json -# cannot use maven project.version here, as file generation happens before building maven -version=`jq .version packages/ts/generator-typescript-core/package.json | cut -d '"' -f 2` -# TODO: compute this number when we maintain multiple hilla branches -branch=24.3.0 - -# download needed files from vaadin/platform -url=https://raw.githubusercontent.com/vaadin -results=./scripts/generator/results/ -src=./scripts/generator/src/ -mkdir -p $results -mkdir -p $src -# Take versions.json -curl -L -s "${url}/platform/${branch}/versions.json" > ${results}/versions.json -perl -pi -e 's/.*{{version}}.*\n//g' ${results}/versions.json -# Take scripts (this allows us not maintain the same scripts twice) -for i in creator replacer transformer writer -do - [ ! -f "${src}/${i}.js" ] && curl -L -s "${url}/platform/${branch}/${src}/${i}.js" > ${src}/${i}.js -done - -# run the generator -cmd="node scripts/generator/generate.js $version scripts/generator/results/versions.json" -echo Running: "$cmd" >&2 -$cmd || exit 1 - -# copy generated poms to the final place -cp scripts/generator/results/hilla-versions.json packages/java/hilla/hilla-versions.json -cp scripts/generator/results/hilla-react-versions.json packages/java/hilla-react/hilla-react-versions.json - -echo "Copied the theme file from flow-components to hilla and hilla-react" -# download the file from flow-components -lumoFile="${url}/flow-components/${branch}/vaadin-lumo-theme-flow-parent/vaadin-lumo-theme-flow/src/main/java/com/vaadin/flow/theme/lumo/Lumo.java" -materialFile="${url}/flow-components/${branch}/vaadin-material-theme-flow-parent/vaadin-material-theme-flow/src/main/java/com/vaadin/flow/theme/material/Material.java" -curl -l -s $lumoFile > ./scripts/generator/results/Lumo.java -curl -l -s $materialFile > ./scripts/generator/results/Material.java - -# remove @JsModule and @NpmPackage annotation and their import lines -perl -pi -e 's/.*(JsModule|NpmPackage).*\n//g' ./scripts/generator/results/Lumo.java ./scripts/generator/results/Material.java - -# copy the theme files to hilla and hilla-react -mkdir -p ./packages/java/hilla-react/src/main/java/com/vaadin/hilla/theme -mkdir -p ./packages/java/hilla/src/main/java/com/vaadin/hilla/theme -cp scripts/generator/results/Lumo.java packages/java/hilla-react/src/main/java/com/vaadin/hilla/theme/Lumo.java -cp scripts/generator/results/Lumo.java packages/java/hilla/src/main/java/com/vaadin/hilla/theme/Lumo.java -cp scripts/generator/results/Material.java packages/java/hilla-react/src/main/java/com/vaadin/hilla/theme/Material.java -cp scripts/generator/results/Material.java packages/java/hilla/src/main/java/com/vaadin/hilla/theme/Material.java diff --git a/scripts/prepare/config.ts b/scripts/prepare/config.ts new file mode 100644 index 0000000000..bea0aa12d8 --- /dev/null +++ b/scripts/prepare/config.ts @@ -0,0 +1,65 @@ +export type Version = { + javaVersion?: string; + jsVersion?: string; + npmName?: string; +}; + +export type Versions = { + bundles: Record; + core: Record; + kits: Record; + platform: string; + react: Record; + vaadin: Record; +}; + +export interface Writer { + writeReleaseNotes(versions: Versions, templateFileName: string, resultFileName: string): void; + writeSeparateJson( + versions: Record | string, + templateFileName: string, + resultFileName: string, + key: keyof Versions, + ): void; +} + +export interface Transformer { + transformVersions(versions: Versions, version: string, isPrerelease: boolean): Versions; +} + +// TODO: compute this number when we maintain multiple hilla branches +export const branch = 'main'; + +export const repoUrl = new URL('https://raw.githubusercontent.com/vaadin/'); +export const root = new URL('../../', import.meta.url); + +export const local = { + src: new URL(`scripts/prepare/src/`, root), + versionedPackageJson: new URL('packages/ts/generator-typescript-core/package.json', root), + results: new URL(`scripts/prepare/results/`, root), +}; + +export const remote = { + // https://raw.githubusercontent.com/vaadin/platform/24.3.0/scripts/generator/src/writer.js + src: new URL(`platform/${branch}/scripts/generator/src/`, repoUrl), + versions: new URL(`platform/${branch}/versions.json`, repoUrl), + lumo: new URL( + `flow-components/${branch}/vaadin-lumo-theme-flow-parent/vaadin-lumo-theme-flow/src/main/java/com/vaadin/flow/theme/lumo/Lumo.java`, + repoUrl, + ), + material: new URL( + `flow-components/${branch}/vaadin-material-theme-flow-parent/vaadin-material-theme-flow/src/main/java/com/vaadin/flow/theme/material/Material.java`, + repoUrl, + ), +}; + +export const destination = { + lit: { + versions: new URL('packages/java/hilla/hilla-versions.json', root), + themeDir: new URL('packages/java/hilla/src/main/java/com/vaadin/hilla/theme/', root), + }, + react: { + versions: new URL('packages/java/hilla-react/hilla-react-versions.json', root), + themeDir: new URL('packages/java/hilla-react/src/main/java/com/vaadin/hilla/theme/', root), + }, +}; diff --git a/scripts/prepare/generate.ts b/scripts/prepare/generate.ts new file mode 100644 index 0000000000..4a82ce5971 --- /dev/null +++ b/scripts/prepare/generate.ts @@ -0,0 +1,120 @@ +/* eslint-disable no-console */ +import { createRequire } from 'node:module'; +import { fileURLToPath, pathToFileURL } from 'node:url'; +import { Script } from 'node:vm'; +import { remote, type Transformer, type Versions, type Writer } from './config.js'; + +const require = createRequire(import.meta.url); + +async function loadScripts(): Promise { + const [creator, replacer, transformer, writer] = await Promise.all( + ['creator', 'replacer', 'transformer', 'writer'].map(async (name) => { + const url = new URL(`./${name}.js`, remote.src); + const res = await fetch(url); + const code = await res.text(); + return new Script(code, { filename: url.toString() }); + }), + ); + + function req(name: string): unknown { + let script: Script; + + if (name.includes('creator')) { + script = creator; + } else if (name.includes('replacer')) { + script = replacer; + } else if (name.includes('writer')) { + script = writer; + } else if (name.includes('transformer')) { + script = transformer; + } else { + return require(name); + } + + const exports = {}; + + const ctx = { + exports, + module: { exports }, + require: req, + }; + script.runInNewContext(ctx); + + return ctx.module.exports; + } + + return [req('writer') as Writer, req('transformer') as Transformer]; +} + +const [writer, transformer] = await loadScripts(); + +const [ + hillaJsonTemplateFileName, + hillaReactJsonTemplateFileName, + releaseNotesTemplateFileName, + releaseNotesMaintenanceTemplateFileName, + releaseNotesPrereleaseTemplateFileName, +] = [ + 'template-hilla-versions.json', + 'template-hilla-react-versions.json', + 'template-release-note.md', + 'template-release-note-maintenance.md', + 'template-release-note-prerelease.md', +].map((name) => fileURLToPath(new URL(`templates/${name}`, import.meta.url))); + +const [ + hillaJsonResultFileName, + hillaReactJsonResultFileName, + releaseNotesResultFileName, + releaseNotesMaintenanceResultFileName, + releaseNotesPrereleaseResultFileName, +] = [ + 'hilla-versions.json', + 'hilla-react-versions.json', + 'release-note.md', + 'release-note-maintenance.md', + 'release-note-prerelease.md', +].map((name) => fileURLToPath(new URL(`results/${name}`, import.meta.url))); + +export default function generate(version: string, versions: Versions): void { + console.log('Generating release files'); + + const transformed = transformer.transformVersions(versions, version, false); + transformed.platform = version; + + writer.writeSeparateJson(transformed.bundles, hillaJsonTemplateFileName, hillaJsonResultFileName, 'bundles'); + writer.writeSeparateJson(transformed.core, hillaJsonTemplateFileName, hillaJsonResultFileName, 'core'); + writer.writeSeparateJson(transformed.vaadin, hillaJsonTemplateFileName, hillaJsonResultFileName, 'vaadin'); + writer.writeSeparateJson( + transformed.bundles, + hillaReactJsonTemplateFileName, + hillaReactJsonResultFileName, + 'bundles', + ); + + console.log(`Generated ${pathToFileURL(hillaJsonResultFileName).toString()}.`); + + writer.writeSeparateJson(transformed.react, hillaReactJsonTemplateFileName, hillaReactJsonResultFileName, 'react'); + + console.log(`Generated ${pathToFileURL(hillaReactJsonResultFileName).toString()}.`); + + writer.writeReleaseNotes(transformed, releaseNotesTemplateFileName, releaseNotesResultFileName); + + console.log(`Generated ${pathToFileURL(releaseNotesResultFileName).toString()}.`); + + writer.writeReleaseNotes(transformed, releaseNotesMaintenanceTemplateFileName, releaseNotesMaintenanceResultFileName); + + console.log(`Generated ${pathToFileURL(releaseNotesMaintenanceResultFileName).toString()}.`); + + writer.writeReleaseNotes(transformed, releaseNotesPrereleaseTemplateFileName, releaseNotesPrereleaseResultFileName); + + console.log(`Generated ${pathToFileURL(releaseNotesPrereleaseResultFileName).toString()}.`); + + transformed.core.hilla = { javaVersion: version }; + + // write hilla version to hilla-react-versions.json as platform + writer.writeSeparateJson(version, hillaJsonTemplateFileName, hillaJsonResultFileName, 'platform'); + writer.writeSeparateJson(version, hillaReactJsonTemplateFileName, hillaReactJsonResultFileName, 'platform'); + + console.log('"hilla-versions.json" and "hilla-react-versions.json" files are updated with the platform version'); +} diff --git a/scripts/prepare/index.ts b/scripts/prepare/index.ts new file mode 100644 index 0000000000..2021ab87e5 --- /dev/null +++ b/scripts/prepare/index.ts @@ -0,0 +1,60 @@ +/* eslint-disable no-console */ +import { copyFile, mkdir, readFile, writeFile } from 'node:fs/promises'; +import type { PackageJson } from 'type-fest'; +import { destination, local, remote, type Versions } from './config.js'; +import generate from './generate.js'; + +const [{ version }, versions] = await Promise.all([ + readFile(local.versionedPackageJson, 'utf-8').then(JSON.parse) as Promise, + // download needed files from vaadin/platform + fetch(remote.versions) + .then(async (res) => await res.text()) + .then((str) => JSON.parse(str, (_, val) => (val === '{{version}}' ? undefined : val))) as Promise, + mkdir(local.src, { recursive: true }), + mkdir(local.results, { recursive: true }), + mkdir(destination.lit.themeDir, { recursive: true }), + mkdir(destination.react.themeDir, { recursive: true }), +]); + +if (!version) { + throw new Error('No version found in package.json of Hilla "generator-typescript-core"'); +} + +// run the generator +generate(version, versions); + +console.log('Moving the generated files to the final place.'); + +await Promise.all([ + copyFile(new URL('hilla-versions.json', local.results), destination.lit.versions).then(() => + console.log(`Moved ${destination.lit.versions.toString()}`), + ), + copyFile(new URL('hilla-react-versions.json', local.results), destination.react.versions).then(() => + console.log(`Moved ${destination.react.versions.toString()}`), + ), +]); + +const themeAnnotationsPattern = /.*(JsModule|NpmPackage).*\n/gmu; +const themeFiles = new Map([ + [remote.lumo, [new URL('Lumo.java', destination.lit.themeDir), new URL('Lumo.java', destination.react.themeDir)]], + [ + remote.material, + [new URL('Material.java', destination.lit.themeDir), new URL('Material.java', destination.react.themeDir)], + ], +]); + +console.log('Copying the theme files from flow-components to the final place.'); + +await Promise.all( + Array.from(themeFiles.entries(), async ([url, dest]) => { + const response = await fetch(url); + let code = await response.text(); + code = code.replaceAll(themeAnnotationsPattern, ''); + await Promise.all( + dest.map(async (file) => { + await writeFile(file, code); + console.log(`Copied ${file.toString()}`); + }), + ); + }), +); diff --git a/scripts/generator/templates/template-hilla-react-versions.json b/scripts/prepare/templates/template-hilla-react-versions.json similarity index 100% rename from scripts/generator/templates/template-hilla-react-versions.json rename to scripts/prepare/templates/template-hilla-react-versions.json diff --git a/scripts/generator/templates/template-hilla-versions.json b/scripts/prepare/templates/template-hilla-versions.json similarity index 100% rename from scripts/generator/templates/template-hilla-versions.json rename to scripts/prepare/templates/template-hilla-versions.json diff --git a/scripts/generator/templates/template-release-note-maintenance.md b/scripts/prepare/templates/template-release-note-maintenance.md similarity index 100% rename from scripts/generator/templates/template-release-note-maintenance.md rename to scripts/prepare/templates/template-release-note-maintenance.md diff --git a/scripts/generator/templates/template-release-note-prerelease.md b/scripts/prepare/templates/template-release-note-prerelease.md similarity index 100% rename from scripts/generator/templates/template-release-note-prerelease.md rename to scripts/prepare/templates/template-release-note-prerelease.md diff --git a/scripts/generator/templates/template-release-note.md b/scripts/prepare/templates/template-release-note.md similarity index 100% rename from scripts/generator/templates/template-release-note.md rename to scripts/prepare/templates/template-release-note.md diff --git a/tsconfig.json b/tsconfig.json index 30d4317833..a4cd12f6a6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,5 +19,5 @@ "useDefineForClassFields": true, "useUnknownInCatchVariables": true }, - "include": ["scripts/*.ts", "scripts/*.d.ts", "./*.ts", "./*.d.ts", "./*.js", "./*.cjs"] + "include": ["scripts/**/*.ts", "scripts/*.d.ts", "./*.ts", "./*.d.ts", "./*.js", "./*.cjs"] }