From c815637797132e0b3f49780622e77d3e15278724 Mon Sep 17 00:00:00 2001 From: Irshad Ahmad Date: Tue, 23 Jan 2024 20:17:45 +0530 Subject: [PATCH 1/6] Improve WP Project detection --- tools/wpdev/src/base-commands/WithProjects.ts | 18 +- tools/wpdev/src/commands/bundle.ts | 8 +- tools/wpdev/src/commands/clean.ts | 6 +- tools/wpdev/src/commands/project-info.ts | 4 +- tools/wpdev/src/utils/projects.ts | 228 +++++++++++++++--- tools/wpdev/src/utils/schema.ts | 11 +- tools/wpdev/src/utils/tools.ts | 32 +-- tools/wpdev/src/utils/wp-files.ts | 93 +++++++ tools/wpdev/src/utils/wp-monorepo.ts | 93 +++---- 9 files changed, 350 insertions(+), 143 deletions(-) create mode 100644 tools/wpdev/src/utils/wp-files.ts diff --git a/tools/wpdev/src/base-commands/WithProjects.ts b/tools/wpdev/src/base-commands/WithProjects.ts index 26d6ab6a..2122628c 100644 --- a/tools/wpdev/src/base-commands/WithProjects.ts +++ b/tools/wpdev/src/base-commands/WithProjects.ts @@ -4,7 +4,7 @@ import { PROJECT_CONFIG_FILE_NAME, ROOT_CONFIG_FILE_NAME, } from '../utils/config.js'; -import { WPProject, getStandalonePackage } from '../utils/tools.js'; +import { WPProject, getStandaloneProject } from '../utils/projects.js'; import { WPMonorepo } from '../utils/wp-monorepo.js'; import { WithRootDirAsCwd } from './WithRootDirAsCwd.js'; @@ -65,7 +65,7 @@ export abstract class WithProjects< const expectedPkgJsonConfig = this.cliConfig.operationMode === 'wp-monorepo' - ? 'wpdev.belongsTo' + ? 'wpdev.projectType' : 'wpdev.isRoot'; messages.push( @@ -99,13 +99,13 @@ export abstract class WithProjects< if (this.cliConfig.operationMode === 'wp-monorepo') { if (this.flags['from-changeset']) { - this.projects = this.wpMonorepo.getProjectsToRelease( + this.projects = await this.wpMonorepo.getProjectsToRelease( this.flags['changeset-json'], ); } else if (this.flags.all) { - this.projects = this.wpMonorepo.getManagedProjects(); + this.projects = await this.wpMonorepo.getManagedProjects(); } else if (argv.length) { - this.projects = this.wpMonorepo.getProjectsByName( + this.projects = await this.wpMonorepo.getProjectsByName( argv as Array, ); } else { @@ -117,7 +117,7 @@ export abstract class WithProjects< } protected async detectProject() { - const project = await getStandalonePackage(this.commandCwd); + const project = await getStandaloneProject(this.commandCwd); if (!project) { throw new Error('Could not detect project.'); @@ -125,8 +125,10 @@ export abstract class WithProjects< this.log('🔍 Detected project: ', chalk.bold(project.packageJson.name)); - if (project.packageJson.wpdev?.belongsTo) { - this.projects = new Map([[project.packageJson.name, project]]); + if (project.wpdev?.projectType) { + this.projects = new Map([ + [project.packageJson.name, project as WPProject], + ]); return; } diff --git a/tools/wpdev/src/commands/bundle.ts b/tools/wpdev/src/commands/bundle.ts index 3ef367b8..36164328 100644 --- a/tools/wpdev/src/commands/bundle.ts +++ b/tools/wpdev/src/commands/bundle.ts @@ -13,13 +13,13 @@ import { } from '../utils/i18n.js'; import { copyFiles, getDistIgnorePattern, zipDir } from '../utils/misc.js'; import { + WPProject, getNextVersion, - getProjectConfig, + getProjectBundleConfig, runScript, } from '../utils/projects.js'; import { updateRequirements } from '../utils/requirements.js'; import { minifyStyles } from '../utils/styles.js'; -import { WPProject } from '../utils/tools.js'; import { updateVersion } from '../utils/versions.js'; type TaskWrapper = Parameters[1]; @@ -146,7 +146,9 @@ export default class Bundle extends WithProjects { async prepareForDist(project: WPProject, task: TaskWrapper) { const version = this.getVersion(project, task); - const { projectInfo, bundle } = await getProjectConfig(project, version); + const projectInfo = project.wpdev; + + const bundle = await getProjectBundleConfig(project); const outDir = this.getOutputDir(project); diff --git a/tools/wpdev/src/commands/clean.ts b/tools/wpdev/src/commands/clean.ts index 7cb1beaa..515e03cd 100644 --- a/tools/wpdev/src/commands/clean.ts +++ b/tools/wpdev/src/commands/clean.ts @@ -237,7 +237,9 @@ export default class Clean extends WithConfig { // It's possible that the connected project may be a git repo // So the above git commands won't work for nested git repos - const connectedProjects = wpMonorepo.getProjects({ connected: true }); + const connectedProjects = await wpMonorepo.getProjects({ + connected: true, + }); for (const [name, project] of connectedProjects) { const files = child_process.execSync( @@ -263,7 +265,7 @@ export default class Clean extends WithConfig { // We do not want to delete any of the project directories in the monorepo. filesToSkip = new Set( - [...wpMonorepo.getAllProjects()].map(([name, project]) => { + [...(await wpMonorepo.getAllProjects())].map(([name, project]) => { return ( // We need posix paths for git pathToPosix(project.relativeDir) diff --git a/tools/wpdev/src/commands/project-info.ts b/tools/wpdev/src/commands/project-info.ts index b5e6fc7b..6c001c83 100644 --- a/tools/wpdev/src/commands/project-info.ts +++ b/tools/wpdev/src/commands/project-info.ts @@ -18,13 +18,13 @@ export default class ProjectInfo extends WithProjects { public async run(): Promise { try { const projects = [...this.projects].map( - ([name, { relativeDir, dir, packageJson }]) => { + ([name, { relativeDir, dir, packageJson, wpdev }]) => { return { name, version: packageJson.version, relativeDir, dir, - wpdev: packageJson.wpdev, + wpdev, }; }, ); diff --git a/tools/wpdev/src/utils/projects.ts b/tools/wpdev/src/utils/projects.ts index 1485e558..453e87a6 100644 --- a/tools/wpdev/src/utils/projects.ts +++ b/tools/wpdev/src/utils/projects.ts @@ -1,14 +1,25 @@ import fs from 'node:fs'; import path from 'node:path'; +import { Package } from '@manypkg/tools'; import { execa } from 'execa'; import { ReleaseType, inc as semverInc } from 'semver'; +import { PROJECT_CONFIG_FILE_NAME } from './config.js'; +import { isFileReadable } from './misc.js'; import { BundleConfigInput, + ProjectInfo, ProjectInfoInput, bundleSchema, projectInfoSchema, } from './schema.js'; -import { WPProject } from './tools.js'; +import { UserConfig, fixPackageType, getStandalonePackage } from './tools.js'; +import { getFileData, zippedFileHeaders } from './wp-files.js'; + +export type ProjectType = NonNullable; + +export type WPProject = Package & { + wpdev: ProjectInfo; +}; export function getNextVersion(project: WPProject, releaseType: string) { return semverInc(project.packageJson.version, releaseType as ReleaseType); @@ -21,64 +32,152 @@ export async function runScript(cwd: string, script: string, pm = 'npm') { } export type ProjectConfig = { - getProjectInfo?: (project: WPProject) => ProjectInfoInput; - getBundleConfig: (options: { - project: WPProject; - slug: string; - key: string; - version?: string; - textDomain: string; - }) => BundleConfigInput; + getProjectInfo?: (project: Package) => ProjectInfoInput; + getBundleConfig: ( + options: Required & { + project: WPProject; + version?: string; + }, + ) => BundleConfigInput; }; -export async function getProjectConfig(project: WPProject, version?: string) { - const configPathRel = path.join(project.relativeDir, 'wpdev.project.js'); +export function pluralizeProjectType(projectType: ProjectType) { + return `${projectType}s` as const; +} - const configPath = path.resolve(configPathRel); +export function singularizeProjectType( + projectType: UserConfig['projectTypes'][number], +) { + return projectType.replace(/s$/, '') as ProjectType; +} - if (!fs.existsSync(configPath)) { - throw new Error(`Project config file not found at "${configPathRel}"`); +/** + * Get the project type e.g. "plugin", "theme", "mu-plugin" + */ +export async function getProjectType( + _pkg: Package, + allowedTypes: UserConfig['projectTypes'], +) { + const pkg = fixPackageType(_pkg); + // If the project type is defined in the package.json + if ( + pkg.packageJson.wpdev?.projectType && + allowedTypes.includes( + pluralizeProjectType(pkg.packageJson.wpdev?.projectType), + ) + ) { + return pkg.packageJson.wpdev.projectType; } - const { getProjectInfo, getBundleConfig } = (await import( - `file:///${configPath}` - )) as ProjectConfig; + // Try to detect the project type from the files in the directory + const projectType = await detectWpProjectType(pkg); + if (projectType) { + return projectType; + } - if (!getBundleConfig || typeof getBundleConfig !== 'function') { - throw new Error( - `Invalid project config at "${configPathRel}".\n\nERRORS: "getBundleConfig" must be a function.`, - ); + // If "projectType" is not defined in package.json, + // we can use the package's parent folder name to determine the project type + // For example `relativeDir: 'plugins/wptelegram-widget'` + if (process.env.WPDEV_DETECT_TYPE_FROM_PARENT_DIR) { + const parentDir = path.basename( + path.dirname(pkg.dir), + ) as UserConfig['projectTypes'][number]; + + if (allowedTypes.includes(parentDir)) { + return singularizeProjectType(parentDir); + } } +} - const projectInfo = getProjectInfo?.(project) || {}; +export async function getProjectInfo( + project: Package, + projectTypes: UserConfig['projectTypes'] = [], +) { + const configPath = path.join(project.dir, PROJECT_CONFIG_FILE_NAME); + const configPathRel = path.relative(process.cwd(), configPath); + + let details = { + slug: '', + key: '', + textDomain: '', + }; - const projectInfoResult = projectInfoSchema.safeParse(projectInfo); + let projectType: ProjectType | undefined; - if (!projectInfoResult.success) { - throw new Error( - `Invalid project config at "${configPathRel}".\n\nERRORS: "${projectInfoResult.error.message}"`, - ); - } + // If we have a config file, get the project info + if (fs.existsSync(configPath)) { + const { getProjectInfo: getUserProjectInfo } = (await import( + `file:///${configPath}` + )) as ProjectConfig; + + const projectInfo = getUserProjectInfo?.(project) || {}; - let { slug, key, textDomain } = projectInfoResult.data; + const projectInfoResult = projectInfoSchema.safeParse(projectInfo); - if (!slug) { + if (!projectInfoResult.success) { + throw new Error( + `Invalid project config at "${configPathRel}".\n\nERRORS: "${projectInfoResult.error.message}"`, + ); + } + + details = { + ...details, + ...projectInfoResult.data, + }; + + // If the project type is defined in the config file, use it + projectType = projectInfoResult.data.projectType; + } + + if (!details.slug) { // If the slug is not defined, use the package name // It can be something like "@wpsocio/plugin-name" const parts = project.packageJson.name.split('/'); - slug = parts[1] || parts[0]; + details.slug = parts[1] || parts[0]; } - if (!key) { - // If the key is not defined, use the slug - key = slug.replace('-', '_'); + // If the key is not defined, use the slug + details.key = details.key || details.slug.replace('-', '_'); + + details.textDomain = details.textDomain || details.slug; + + // If the project type is not defined in the config file, don't give up! + projectType = projectType || (await getProjectType(project, projectTypes)); + + return { ...details, projectType }; +} + +type ProjectBundleConfigOptions = { + globalConfig?: string; +}; + +export async function getProjectBundleConfig( + project: WPProject, + { globalConfig }: ProjectBundleConfigOptions = {}, +) { + const configPath = path.join(project.dir, PROJECT_CONFIG_FILE_NAME); + const configPathRel = path.relative(process.cwd(), configPath); + + if ( + !fs.existsSync(configPath) && + (!globalConfig || !fs.existsSync(globalConfig)) + ) { + throw new Error(`Project config file not found at "${configPathRel}"`); } - textDomain = textDomain || slug; + const { getBundleConfig } = (await import( + `file:///${configPath || path.resolve(globalConfig || '')}` + )) as ProjectConfig; + + if (!getBundleConfig || typeof getBundleConfig !== 'function') { + throw new Error( + `Invalid project config at "${configPathRel}".\n\nERRORS: "getBundleConfig" must be a function.`, + ); + } const bundleResult = bundleSchema.safeParse( - getBundleConfig({ project, slug, key, version, textDomain }), + getBundleConfig({ project, ...project.wpdev }), ); if (!bundleResult.success) { @@ -87,8 +186,57 @@ export async function getProjectConfig(project: WPProject, version?: string) { ); } - return { - projectInfo: { ...projectInfo, slug, key, textDomain }, - bundle: bundleResult.data, - }; + return bundleResult.data; +} + +export async function getStandaloneProject(dir: string) { + const pkg = await getStandalonePackage(dir); + + if (pkg) { + const wpdev = await getProjectInfo(pkg); + return { ...pkg, wpdev }; + } + + return pkg; +} + +/** + * Detect WP project from the files in the directory + */ +export async function detectWpProjectType( + pkg: Package, +): Promise { + const entries = fs.readdirSync(pkg.dir, { withFileTypes: true }); + + for (const dirent of entries) { + if (!dirent.isFile()) { + continue; + } + + const file = path.join(pkg.dir, dirent.name); + + if (!isFileReadable(file)) { + return undefined; + } + + const fileInfo = path.parse(file); + + if (fileInfo.ext === '.css' && fileInfo.name === 'style') { + const data = await getFileData(file, zippedFileHeaders('theme')); + + // If the file has a theme name, it's a theme + if (data['Theme Name']) { + return 'theme'; + } + } + + if (fileInfo.ext === '.php') { + const data = await getFileData(file, zippedFileHeaders('plugin')); + + // If the file has a plugin name, it's a plugin + if (data['Plugin Name']) { + return 'plugin'; + } + } + } } diff --git a/tools/wpdev/src/utils/schema.ts b/tools/wpdev/src/utils/schema.ts index 4f2a5e22..239ebd63 100644 --- a/tools/wpdev/src/utils/schema.ts +++ b/tools/wpdev/src/utils/schema.ts @@ -1,4 +1,5 @@ import { z } from 'zod'; +import { UserConfigSchema } from './tools.js'; const targetFilesSchema = z.object({ files: z @@ -231,10 +232,6 @@ export type BundleConfigInput = z.input; export type BundleConfig = z.infer; export const projectInfoSchema = z.object({ - title: z - .string() - .optional() - .describe('The project title. e.g. "WP Telegram Login".'), key: z .string() .optional() @@ -251,10 +248,14 @@ export const projectInfoSchema = z.object({ .string() .optional() .describe('The text domain for i18n e.g. "wptelegram-login".'), + projectType: z + .enum(['plugin', 'theme', 'mu-plugin']) + .optional() + .describe('The project type.'), }); export type ProjectInfoInput = z.input; -export type ProjectInfo = z.infer; +export type ProjectInfo = Required>; export const projectSchema = z.object({ project: projectInfoSchema.optional(), diff --git a/tools/wpdev/src/utils/tools.ts b/tools/wpdev/src/utils/tools.ts index 77c24b32..9065d129 100644 --- a/tools/wpdev/src/utils/tools.ts +++ b/tools/wpdev/src/utils/tools.ts @@ -1,6 +1,7 @@ import { getPackages } from '@manypkg/get-packages'; import { Package, RootTool } from '@manypkg/tools'; import { z } from 'zod'; +import { projectInfoSchema } from './schema.js'; export const UserConfigSchema = z .object({ @@ -20,12 +21,9 @@ export const UserConfigSchema = z .describe( 'The project types managed by this monorepo. Only used in wp-monorepo mode.', ), - belongsTo: z - .enum(['plugins', 'themes', 'mu-plugins']) - .optional() - .describe( - 'The project type this project belongs to. Used for individual packages in a monorepo or for standalone projects.', - ), + projectType: projectInfoSchema.shape.projectType.describe( + 'The project type. Used for individual packages in a monorepo or for standalone projects.', + ), envFiles: z .array(z.string()) .optional() @@ -48,31 +46,18 @@ export type UserConfigInput = z.input; export type UserConfig = z.infer; -export type ProjectType = NonNullable[number]; - export type PackageJSON = Package['packageJson'] & { wpdev?: UserConfigInput; }; -export type WPProject = Omit & { +export type StandalonePackage = Omit & { packageJson: PackageJSON; }; /** * Fix the type of the package json to include the wpdev config. */ -export function fixPackage(pkg: Package): WPProject { - if ('wpdev' in pkg.packageJson && pkg.packageJson.wpdev) { - const wpdev = UserConfigSchema.parse(pkg.packageJson.wpdev); - - return { - ...pkg, - packageJson: { - ...pkg.packageJson, - wpdev, - }, - }; - } +export function fixPackageType(pkg: Package): StandalonePackage { return pkg; } @@ -81,7 +66,6 @@ export async function getStandalonePackage(dir: string) { tools: [RootTool], }); - const [pkg] = packages; - - return pkg ? fixPackage(pkg) : pkg; + // We need only the first package + return fixPackageType(packages[0]); } diff --git a/tools/wpdev/src/utils/wp-files.ts b/tools/wpdev/src/utils/wp-files.ts new file mode 100644 index 00000000..6a23354c --- /dev/null +++ b/tools/wpdev/src/utils/wp-files.ts @@ -0,0 +1,93 @@ +import fs from 'node:fs'; + +export async function readFileBytes( + path: string, + endAt: number, +): Promise { + const chunks = []; + + const options = { start: 0, end: endAt }; + + for await (const chunk of fs.createReadStream(path, options)) { + chunks.push(chunk); + } + return Buffer.concat(chunks).toString(); +} + +export async function getFileData( + file: string, + headers: Record, +) { + // Read only the first 8kiB of the file in. + let fileData = await readFileBytes(file, 8192); + + fileData = fileData.replace(/\r/g, '\n'); + + return getFileDataFromString(fileData, headers); +} + +/** + * Retrieves metadata from a string. + */ +export function getFileDataFromString( + text: string, + headers: Record, +) { + const data: Record = {}; + + for (const [field, regex] of Object.entries(headers)) { + const re = new RegExp(`^[ \t\/*#@]*${regex}:(.*)$`, 'mi'); + + const match = text.match(re); + + if (match?.[1]) { + data[field] = cleanupHeaderComment(match[1]); + } else { + data[field] = ''; + } + } + + return data; +} + +/** + * Strip close comment and close php tags from file headers used by WP. + */ +export function cleanupHeaderComment(str: string) { + return str.replace(/\s*(?:\*\/|\?>).*/g, '').trim(); +} + +/** + * Returns the file headers for themes and plugins. + */ +export function getFileHeaders(type: 'plugin' | 'theme') { + const common = [ + 'Description', + 'Author', + 'Author URI', + 'Version', + 'License', + 'Domain Path', + 'Text Domain', + ]; + + const headers = { + plugin: ['Plugin Name', 'Plugin URI', ...common], + theme: ['Theme Name', 'Theme URI', ...common], + }; + + return headers[type] || []; +} + +export function zippedFileHeaders(type: 'plugin' | 'theme') { + const headers = getFileHeaders(type); + + return headers.reduce( + (acc, header) => { + acc[header] = header; + + return acc; + }, + {} as Record, + ); +} diff --git a/tools/wpdev/src/utils/wp-monorepo.ts b/tools/wpdev/src/utils/wp-monorepo.ts index c1796d15..70e19dab 100644 --- a/tools/wpdev/src/utils/wp-monorepo.ts +++ b/tools/wpdev/src/utils/wp-monorepo.ts @@ -2,7 +2,8 @@ import path from 'node:path'; import { getPackagesSync } from '@manypkg/get-packages'; import { execaSync } from 'execa'; import { readChangesetJson } from './changelog.js'; -import { ProjectType, UserConfig, WPProject, fixPackage } from './tools.js'; +import { WPProject, getProjectInfo, pluralizeProjectType } from './projects.js'; +import { UserConfig } from './tools.js'; export type WPMonorepoConfig = { rootDir: string; @@ -63,55 +64,29 @@ export class WPMonorepo { } } - getProjectsByType(projectTypes: Array) { + async getWpPackages() { const { packages } = getPackagesSync(this.config.rootDir); - const projects: Array = []; + const projects = await Promise.all( + packages.map(async (pkg) => { + const wpdev = await getProjectInfo(pkg, this.config.projectTypes); - for (const _pkg of packages) { - const pkg = fixPackage(_pkg); - - let projectType: ProjectType | undefined; - - // If "belongsTo" is defined - if (pkg.packageJson.wpdev?.belongsTo) { - if (projectTypes.includes(pkg.packageJson.wpdev?.belongsTo)) { - projectType = pkg.packageJson.wpdev?.belongsTo; - } - } else { - // If "belongsTo" is not defined, we can use the package's parent folder name to determine the project type - // For example `relativeDir: 'plugins/wptelegram-widget'` - const parentDir = path.basename(path.dirname(pkg.dir)) as ProjectType; - - if (projectTypes.includes(parentDir)) { - projectType = parentDir; - } - } - - if (projectType) { - projects.push({ - ...pkg, - packageJson: { - ...pkg.packageJson, - wpdev: { - ...pkg.packageJson.wpdev, - belongsTo: projectType, - }, - }, - }); - } - } + return { ...pkg, wpdev }; + }), + ); - return projects; + return projects.filter( + (project) => project.wpdev.projectType, + ) as Array; } /** * Get projects. */ - getProjects(include: IncludeOptions) { + async getProjects(include: IncludeOptions) { const projects = new Map(); - for (const project of this.getProjectsByType(this.config.projectTypes)) { + for (const project of await this.getWpPackages()) { const status = this.getProjectStatus(project); if (include[status]) { @@ -122,19 +97,23 @@ export class WPMonorepo { return projects; } - getManagedProjects() { - return this.getProjects({ connected: true, tracked: true }); + async getManagedProjects() { + return await this.getProjects({ connected: true, tracked: true }); } - getAllProjects() { - return this.getProjects({ connected: true, tracked: true, ignored: true }); + async getAllProjects() { + return await this.getProjects({ + connected: true, + tracked: true, + ignored: true, + }); } - getProjectsByName( + async getProjectsByName( projectNames: Array, { throwIfNotFound = true }: { throwIfNotFound?: boolean } = {}, ) { - const managedProjects = this.getManagedProjects(); + const managedProjects = await this.getManagedProjects(); const projects = new Map(); @@ -156,27 +135,23 @@ export class WPMonorepo { /** * Get the symlink path for an item */ - getSymlinkPath( - { packageJson: { name, wpdev } }: WPProject, - wpContentDir: string, - ) { - // TODO: Use project config to get this info - // use the package name as the slug - // It can be something like "@wpsocio/plugin-name" - const parts = name.split('/'); - - const slug = parts[1] || parts[0]; - - return path.join(wpContentDir, wpdev?.belongsTo || '', slug); + getSymlinkPath({ wpdev }: WPProject, wpContentDir: string) { + return path.join( + wpContentDir, + pluralizeProjectType(wpdev.projectType), + wpdev.slug, + ); } - getProjectsToRelease(changesetJsonFile: string) { + async getProjectsToRelease(changesetJsonFile: string) { const projectNames = readChangesetJson(changesetJsonFile) // Get the names of projects that have changesets, ignoring the ones that don't .releases.filter(({ changesets }) => changesets.length) // Collect the names .map((release) => release.name); - return this.getProjectsByName(projectNames, { throwIfNotFound: false }); + return await this.getProjectsByName(projectNames, { + throwIfNotFound: false, + }); } } From e870b538c7462d301da39ba6bd5327f7fe80c765 Mon Sep 17 00:00:00 2001 From: Irshad Ahmad Date: Tue, 23 Jan 2024 20:28:28 +0530 Subject: [PATCH 2/6] Fix zip archive version --- tools/wpdev/src/commands/bundle.ts | 2 +- tools/wpdev/src/utils/projects.ts | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/wpdev/src/commands/bundle.ts b/tools/wpdev/src/commands/bundle.ts index 36164328..cf379e48 100644 --- a/tools/wpdev/src/commands/bundle.ts +++ b/tools/wpdev/src/commands/bundle.ts @@ -148,7 +148,7 @@ export default class Bundle extends WithProjects { const projectInfo = project.wpdev; - const bundle = await getProjectBundleConfig(project); + const bundle = await getProjectBundleConfig(project, { version }); const outDir = this.getOutputDir(project); diff --git a/tools/wpdev/src/utils/projects.ts b/tools/wpdev/src/utils/projects.ts index 453e87a6..754475ba 100644 --- a/tools/wpdev/src/utils/projects.ts +++ b/tools/wpdev/src/utils/projects.ts @@ -36,7 +36,7 @@ export type ProjectConfig = { getBundleConfig: ( options: Required & { project: WPProject; - version?: string; + version: string; }, ) => BundleConfigInput; }; @@ -149,12 +149,13 @@ export async function getProjectInfo( } type ProjectBundleConfigOptions = { + version: string; globalConfig?: string; }; export async function getProjectBundleConfig( project: WPProject, - { globalConfig }: ProjectBundleConfigOptions = {}, + { globalConfig, version }: ProjectBundleConfigOptions, ) { const configPath = path.join(project.dir, PROJECT_CONFIG_FILE_NAME); const configPathRel = path.relative(process.cwd(), configPath); @@ -177,7 +178,7 @@ export async function getProjectBundleConfig( } const bundleResult = bundleSchema.safeParse( - getBundleConfig({ project, ...project.wpdev }), + getBundleConfig({ project, ...project.wpdev, version }), ); if (!bundleResult.success) { From 58a30e850edde031f313dd098009cba005cdb82e Mon Sep 17 00:00:00 2001 From: Irshad Ahmad Date: Tue, 23 Jan 2024 20:59:02 +0530 Subject: [PATCH 3/6] Detect text domain from project main file --- tools/wpdev/src/utils/projects.ts | 32 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/tools/wpdev/src/utils/projects.ts b/tools/wpdev/src/utils/projects.ts index 754475ba..2aa86042 100644 --- a/tools/wpdev/src/utils/projects.ts +++ b/tools/wpdev/src/utils/projects.ts @@ -69,12 +69,6 @@ export async function getProjectType( return pkg.packageJson.wpdev.projectType; } - // Try to detect the project type from the files in the directory - const projectType = await detectWpProjectType(pkg); - if (projectType) { - return projectType; - } - // If "projectType" is not defined in package.json, // we can use the package's parent folder name to determine the project type // For example `relativeDir: 'plugins/wptelegram-widget'` @@ -100,10 +94,9 @@ export async function getProjectInfo( slug: '', key: '', textDomain: '', + ...(await detectWpProject(project)), }; - let projectType: ProjectType | undefined; - // If we have a config file, get the project info if (fs.existsSync(configPath)) { const { getProjectInfo: getUserProjectInfo } = (await import( @@ -120,17 +113,19 @@ export async function getProjectInfo( ); } + console.log('>>>>>>>>>>>>>>>>>>>>', projectInfoResult.data); + details = { ...details, ...projectInfoResult.data, }; - - // If the project type is defined in the config file, use it - projectType = projectInfoResult.data.projectType; } + // If slug is not defined, use the text domain + details.slug = details.slug || details.textDomain; + if (!details.slug) { - // If the slug is not defined, use the package name + // If the slug is still not defined, use the package name // It can be something like "@wpsocio/plugin-name" const parts = project.packageJson.name.split('/'); @@ -143,9 +138,10 @@ export async function getProjectInfo( details.textDomain = details.textDomain || details.slug; // If the project type is not defined in the config file, don't give up! - projectType = projectType || (await getProjectType(project, projectTypes)); + details.projectType = + details.projectType || (await getProjectType(project, projectTypes)); - return { ...details, projectType }; + return details; } type ProjectBundleConfigOptions = { @@ -204,9 +200,9 @@ export async function getStandaloneProject(dir: string) { /** * Detect WP project from the files in the directory */ -export async function detectWpProjectType( +export async function detectWpProject( pkg: Package, -): Promise { +): Promise<{ projectType: ProjectType; textDomain: string } | undefined> { const entries = fs.readdirSync(pkg.dir, { withFileTypes: true }); for (const dirent of entries) { @@ -227,7 +223,7 @@ export async function detectWpProjectType( // If the file has a theme name, it's a theme if (data['Theme Name']) { - return 'theme'; + return { projectType: 'theme', textDomain: data['Text Domain'] }; } } @@ -236,7 +232,7 @@ export async function detectWpProjectType( // If the file has a plugin name, it's a plugin if (data['Plugin Name']) { - return 'plugin'; + return { projectType: 'plugin', textDomain: data['Text Domain'] }; } } } From 5bddab037ac52c89a0aa8c91f9e8c53abb3edf13 Mon Sep 17 00:00:00 2001 From: Irshad Ahmad Date: Tue, 23 Jan 2024 21:00:14 +0530 Subject: [PATCH 4/6] Update project config --- plugins/wptelegram-comments/wpdev.project.js | 2 -- plugins/wptelegram-login/wpdev.project.js | 2 -- plugins/wptelegram-widget/wpdev.project.js | 2 -- plugins/wptelegram/wpdev.project.js | 2 -- 4 files changed, 8 deletions(-) diff --git a/plugins/wptelegram-comments/wpdev.project.js b/plugins/wptelegram-comments/wpdev.project.js index 09c2a455..0fca863c 100644 --- a/plugins/wptelegram-comments/wpdev.project.js +++ b/plugins/wptelegram-comments/wpdev.project.js @@ -3,10 +3,8 @@ * @type {import("@wpsocio/wpdev").ProjectConfig['getProjectInfo']} */ export const getProjectInfo = () => ({ - title: 'WP Telegram Comments', key: 'wptelegram_comments', slug: 'wptelegram-comments', - textDomain: 'wptelegram-comments', }); export { getBundleConfig } from '../wpdev.base.project.js'; diff --git a/plugins/wptelegram-login/wpdev.project.js b/plugins/wptelegram-login/wpdev.project.js index 3a26c115..f8691abd 100644 --- a/plugins/wptelegram-login/wpdev.project.js +++ b/plugins/wptelegram-login/wpdev.project.js @@ -3,10 +3,8 @@ * @type {import("@wpsocio/wpdev").ProjectConfig['getProjectInfo']} */ export const getProjectInfo = () => ({ - title: 'WP Telegram Login', key: 'wptelegram_login', slug: 'wptelegram-login', - textDomain: 'wptelegram-login', }); export { getBundleConfig } from '../wpdev.base.project.js'; diff --git a/plugins/wptelegram-widget/wpdev.project.js b/plugins/wptelegram-widget/wpdev.project.js index a06af37d..a608f249 100644 --- a/plugins/wptelegram-widget/wpdev.project.js +++ b/plugins/wptelegram-widget/wpdev.project.js @@ -3,10 +3,8 @@ * @type {import("@wpsocio/wpdev").ProjectConfig['getProjectInfo']} */ export const getProjectInfo = () => ({ - title: 'WP Telegram Widget', key: 'wptelegram_widget', slug: 'wptelegram-widget', - textDomain: 'wptelegram-widget', }); export { getBundleConfig } from '../wpdev.base.project.js'; diff --git a/plugins/wptelegram/wpdev.project.js b/plugins/wptelegram/wpdev.project.js index aa9429f8..f9639bac 100644 --- a/plugins/wptelegram/wpdev.project.js +++ b/plugins/wptelegram/wpdev.project.js @@ -3,10 +3,8 @@ * @type {import("@wpsocio/wpdev").ProjectConfig['getProjectInfo']} */ export const getProjectInfo = () => ({ - title: 'WP Telegram', key: 'wptelegram', slug: 'wptelegram', - textDomain: 'wptelegram', }); export { getBundleConfig } from '../wpdev.base.project.js'; From 5671735d4eeb0f87408959cd13a7ce0beee9c5ba Mon Sep 17 00:00:00 2001 From: Irshad Ahmad Date: Tue, 23 Jan 2024 21:02:27 +0530 Subject: [PATCH 5/6] Add bundle to PR checks --- .github/workflows/pr-checks.yml | 3 +++ package.json | 1 + 2 files changed, 4 insertions(+) diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 56604d9e..f861a79f 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -66,3 +66,6 @@ jobs: - name: Build run: pnpm build + + - name: Bundle + run: pnpm bundle:all diff --git a/package.json b/package.json index a7e612ea..541d6231 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "type": "module", "scripts": { "build": "wireit", + "bundle:all": "wpdev bundle --all", "bundle:changed": "wireit", "dev": "wireit", "dev:cleanup": "wireit", From d0c266f3a7e71652c4a58a71f3e6d4516d218c1b Mon Sep 17 00:00:00 2001 From: Irshad Ahmad Date: Tue, 23 Jan 2024 21:16:49 +0530 Subject: [PATCH 6/6] Update projects.ts --- tools/wpdev/src/utils/projects.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/wpdev/src/utils/projects.ts b/tools/wpdev/src/utils/projects.ts index 2aa86042..06d23b14 100644 --- a/tools/wpdev/src/utils/projects.ts +++ b/tools/wpdev/src/utils/projects.ts @@ -113,8 +113,6 @@ export async function getProjectInfo( ); } - console.log('>>>>>>>>>>>>>>>>>>>>', projectInfoResult.data); - details = { ...details, ...projectInfoResult.data,