phpxui 0.1.5 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1 -1
- package/dist/commands/icons.js +1 -1
- package/dist/utils/phpxui-ai-context.js +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readFile}from"node:fs/promises";import prompts from"prompts";import chalk from"chalk";import path from"path";import{kebabCase}from"change-case";import{installIcons}from"./commands/icons.js";import{generateComponent}from"./generators/php-component.js";import{generateAllComponents}from"./generators/php-components-bulk.js";import{ensurePackageInstalled}from"./generators/ensure-package.js";import{copyTailwindCss}from"./generators/copy-tailwind.js";import{loadPhpXUIConfig}from"./utils/load-config.js";import{refreshPhpXUIProjectContext}from"./utils/phpxui-ai-context.js";import{getInstalledComponents}from"./utils/scan-installed.js";const PPIconsPattern=/\\PPIcons\\([A-Za-z][A-Za-z0-9]*)\b/g;export async function collectComponentIcons(e,o){const t=new Set;for(const n of e){const e=path.isAbsolute(n)?n:path.resolve(o,n),a=await readFile(e,"utf8");for(const e of a.matchAll(PPIconsPattern))t.add(kebabCase(e[1]))}return[...t].sort((e,o)=>e.localeCompare(o))}const CORE_COMPONENTS=["Slot","Portal"],defaultDependencies={prompts,generateComponent,generateAllComponents,ensurePackageInstalled,copyTailwindCss,loadPhpXUIConfig,getInstalledComponents,collectComponentIcons,installIcons,refreshAiContext:refreshPhpXUIProjectContext,logger:console};export async function runCli(e=process.argv.slice(2),o={}){const t={...defaultDependencies,...o},[n,...a]=e;if("add"!==n&&"update"!==n)return t.logger.log(chalk.blue("Usage: phpxui <add|update> [--all] [--force] <component…>")),0;const s={all:!1,force:!1},r=[];for(let e=0;e<a.length;e++){const o=a[e];switch(o){case"--all":s.all=!0;break;case"--force":s.force=!0;break;default:r.push(o)}}const l=process.cwd(),{config:c,isFirstRun:
|
|
1
|
+
import{readFile}from"node:fs/promises";import prompts from"prompts";import chalk from"chalk";import path from"path";import{kebabCase}from"change-case";import{installIcons}from"./commands/icons.js";import{generateComponent}from"./generators/php-component.js";import{generateAllComponents}from"./generators/php-components-bulk.js";import{ensurePackageInstalled}from"./generators/ensure-package.js";import{copyTailwindCss}from"./generators/copy-tailwind.js";import{loadPhpXUIConfig}from"./utils/load-config.js";import{refreshPhpXUIProjectContext}from"./utils/phpxui-ai-context.js";import{getInstalledComponents}from"./utils/scan-installed.js";const PPIconsPattern=/\\PPIcons\\([A-Za-z][A-Za-z0-9]*)\b/g;export async function collectComponentIcons(e,o){const t=new Set;for(const n of e){const e=path.isAbsolute(n)?n:path.resolve(o,n),a=await readFile(e,"utf8");for(const e of a.matchAll(PPIconsPattern))t.add(kebabCase(e[1]))}return[...t].sort((e,o)=>e.localeCompare(o))}const CORE_COMPONENTS=["Slot","Portal"],defaultDependencies={prompts,generateComponent,generateAllComponents,ensurePackageInstalled,copyTailwindCss,loadPhpXUIConfig,getInstalledComponents,collectComponentIcons,installIcons,refreshAiContext:refreshPhpXUIProjectContext,logger:console};export async function runCli(e=process.argv.slice(2),o={}){const t={...defaultDependencies,...o},[n,...a]=e;if("add"!==n&&"update"!==n)return t.logger.log(chalk.blue("Usage: phpxui <add|update> [--all] [--force] <component…>")),0;const s={all:!1,force:!1},r=[];for(let e=0;e<a.length;e++){const o=a[e];switch(o){case"--all":s.all=!0;break;case"--force":s.force=!0;break;default:r.push(o)}}const l=process.cwd(),{config:c,isFirstRun:i}=t.loadPhpXUIConfig();t.ensurePackageInstalled("tw-animate-css");if(t.copyTailwindCss(i)){const e=path.relative(l,"src/app/globals.css").replace(/\\/g,"/");t.logger.log(chalk.green(i?`✔ Installed base Tailwind CSS → ${e}`:`✔ Added Tailwind CSS (missing) → ${e}`))}const p=path.resolve(l,c.outputDir||"src/Lib/PHPXUI"),g=()=>t.refreshAiContext({projectRoot:l,targetDir:p,config:c}),m=async(e,o={})=>{const n=0===e.length?[]:await t.collectComponentIcons(e,l);await t.installIcons(n,o)};try{if("update"===n){t.logger.log(chalk.blue(`🔎 Scanning for installed components in ${c.outputDir}...`));const e=t.getInstalledComponents(p);if(0===e.length)return await g(),t.logger.log(chalk.yellow("⚠ No components found to update.")),0;t.logger.log(chalk.blue(`✨ Found ${e.length} components. Updating...`));const o=[],n=[],a=[];for(const s of e)try{const e=await t.generateComponent(s,p,!0),n=Array.isArray(e)?e:[e];a.push(...n),n.forEach(e=>o.push(path.basename(e))),t.logger.log(chalk.green(`✔ Updated ${s}`))}catch(e){n.push(`${s}: ${e.message}`),t.logger.log(chalk.red(`✖ Failed to update ${s}`))}return await m(a),await g(),t.logger.log(chalk.green(`\n✔ Successfully updated ${o.length} components.`)),n.length>0&&(t.logger.log(chalk.red(`✖ ${n.length} failures:`)),n.forEach(e=>t.logger.log(` - ${e}`))),0}const e=i||s.force;if(s.all){const{ok:o,fail:n}=await t.generateAllComponents(p,e);return await m(o,{includeRequiredIcons:i}),await g(),n.length?1:0}if(0===r.length){const e=(await t.prompts({type:"text",name:"componentList",message:"Which components do you want to add? (space- or comma-separated)",validate:e=>!!e.trim()||"Enter at least one name"})).componentList;if(!e)return 0;r.push(...e.split(/[\s,]+/))}if(i&&!s.all)for(const e of CORE_COMPONENTS){r.some(o=>o.toLowerCase()===e.toLowerCase())||r.unshift(e)}const o=[];for(const n of r){const a=await t.generateComponent(n,p,e),s=Array.isArray(a)?a:[a];o.push(...s);for(const e of s){const o=path.relative(process.cwd(),e).replace(/\\/g,"/");t.logger.log(chalk.green(`✔ ${n} → ${o}`))}}return await m(o,{includeRequiredIcons:i}),await g(),0}catch(e){return t.logger.error(chalk.red("✖ Error:"),e.message),1}}
|
package/dist/commands/icons.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{execSync}from"child_process";import chalk from"chalk";export const REQUIRED_PHPXUI_ICONS=["chevron-down","x","chevron-right","ellipsis","chevron-left","arrow-left","arrow-right","check","chevrons-up-down","search","circle","calendar","minus","chevron-up","panel-left"];export function resolvePhpXUIIcons(
|
|
1
|
+
import{execSync}from"child_process";import chalk from"chalk";export const REQUIRED_PHPXUI_ICONS=["chevron-down","x","chevron-right","ellipsis","chevron-left","arrow-left","arrow-right","check","chevrons-up-down","search","circle","calendar","minus","chevron-up","panel-left"];export function resolvePhpXUIIcons(n,e={}){const o=[],c=new Set,s=e.includeRequiredIcons?[...REQUIRED_PHPXUI_ICONS,...n]:n;for(const n of s){const e=n.trim().toLowerCase();e&&!c.has(e)&&(c.add(e),o.push(e))}return o}function ensurePPIconsInstalled(){try{execSync("npm list -g ppicons --depth=0",{stdio:"ignore"})}catch{console.log(chalk.blue("📦 Installing ppicons CLI...")),execSync("npm install -g ppicons",{stdio:"inherit"})}}export async function installIcons(n,e={}){const o=resolvePhpXUIIcons(n,e);if(0!==o.length)try{ensurePPIconsInstalled();const n=o.join(" ");console.log(chalk.blue(`✨ Installing required icons: ${n}`)),execSync(`npx ppicons add ${n}`,{stdio:"inherit"}),console.log(chalk.green("✔ Icons installed in src/Lib/PPIcons"))}catch(n){console.error(chalk.red("✖ Failed to install icons:"),n.message),process.exit(1)}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import fs from"fs-extra";import path from"node:path";import{PHPXUI_CONFIG_FILE,PHPXUI_INSTRUCTIONS_FILE,PHPXUI_MANIFEST_KEY,buildPhpXUIManifest,writePhpXUIManifestToConfig}from"./phpxui-manifest.js";const START_MARKER="\x3c!-- phpxui:start --\x3e",END_MARKER="\x3c!-- phpxui:end --\x3e";function getPhpXUIInstructionsPath(e){return path.join(e,...PHPXUI_INSTRUCTIONS_FILE.split("/"))}function escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function buildApplyTo(e){return[PHPXUI_CONFIG_FILE,e.project.hostFrameworkConfigFile,e.project.instructionsFile,`${e.project.componentsDirectory}/**`,e.tailwind.css].join(", ")}function buildInstructionScaffold(e){return["---",'description: "Use when working with PHPXUI, PHPXUI CLI-managed Prisma PHP components, phpxui.json manifest metadata, component installation, component updates, or generated component imports."','name: "PHPXUI AI Context"',`applyTo: "${buildApplyTo(e)}"`,"---","","# PHPXUI Instructions","","Keep PHPXUI-specific AI guidance here instead of in `.github/copilot-instructions.md` or `AGENTS.md`.","",`- Use \`${PHPXUI_CONFIG_FILE}\` under the \`${PHPXUI_MANIFEST_KEY}\` key as the source of truth for installed component inventory, configured paths, and registry metadata.`,"- Prefer `phpxui add ...` or `phpxui update` for registry-backed components instead of hand-writing generated PHPXUI classes.",`- Preserve manual content outside the managed PHPXUI block because refreshes replace only the \`${START_MARKER}\` ... \`${END_MARKER}\` section.`].join("\n")}function getPhpUsageExample(e){return["```php","<?php","",`use ${e}\\Alert;`,"","?>","","<Alert>"," <div>Saved changes</div>","</Alert>","```"].join("\n")}function getCatalogResponseExample(){return["```json","{",' "name": "Button",',' "content": "<?php\\n\\nnamespace Lib\\\\PHPXUI;\\n\\nuse PP\\\\PHPX\\\\PHPX;\\nuse Lib\\\\PHPXUI\\\\Slot;\\n\\nclass Button extends PHPX\\n{\\n ...generated PHP source...\\n}"',"}","```"].join("\n")}function buildManagedBlockContent(e){const n=e.components.length>0?e.components.map(e=>`- ${e.name}: \`${e.file}\``):["- No PHPXUI components are installed yet."];return["# PHPXUI AI Context","","This project uses `phpxui` to generate reusable PHPXUI components for Prisma PHP.","",`- Host framework: ${e.project.hostFramework}`,`- Prisma PHP root config: ${e.project.hostFrameworkConfigFile}`,`- PHPXUI instructions file: ${e.project.instructionsFile}`,`- Components directory: ${e.project.componentsDirectory}`,`- Installed component count: ${e.components.length}`,`- Component namespace: ${e.usage.entry}`,`- Tailwind CSS file: ${e.tailwind.css}`,`- Installed component inventory and project metadata: \`${PHPXUI_CONFIG_FILE}\` (under \`${PHPXUI_MANIFEST_KEY}\`)`,"","## Installing Components","","When a requested UI component does not exist yet, install it with `phpxui` instead of hand-writing generated PHPXUI classes.","",`- Add one component: \`${e.commands.addOne}\``,`- Add multiple components: \`${e.commands.addMany}\``,`- Add the full catalogue: \`${e.commands.addAll}\``,`- Refresh installed components: \`${e.commands.updateInstalled}\``,"","## Discovering Available Components","","Use the PHPXUI catalogue API to find component names before installing them.","",`- Fetch all available components: \`${e.catalogApi.listAll.method} ${e.catalogApi.listAll.url}\``,`- Fetch one component by name: \`${e.catalogApi.getOne.method} ${e.catalogApi.getOne.exampleUrl}\``,"- The `component=all` endpoint returns a JSON array of component objects.","- The single-component endpoint returns one JSON object with `name` and `content` fields.","","Single component response example:","",getCatalogResponseExample(),"","## Installed Components","",...n,"","## Using Installed Components","",`Import generated components from the \`${e.usage.entry}\` namespace and render them as PHPX tags.`,"",getPhpUsageExample(e.usage.entry),"","## Notes","",`- Reuse installed components from \`${PHPXUI_CONFIG_FILE}\` before generating new ones.`,`- Generated component files follow this pattern: \`${e.usage.filePattern}\``,"- Manual content outside this managed block is preserved."].join("\n")}function mergeManagedBlock(e,n){const t=e.replace(/\r\n/g,"\n"),o=new RegExp(
|
|
1
|
+
import fs from"fs-extra";import path from"node:path";import{PHPXUI_CONFIG_FILE,PHPXUI_INSTRUCTIONS_FILE,PHPXUI_MANIFEST_KEY,buildPhpXUIManifest,writePhpXUIManifestToConfig}from"./phpxui-manifest.js";const START_MARKER="\x3c!-- phpxui:start --\x3e",END_MARKER="\x3c!-- phpxui:end --\x3e";function getPhpXUIInstructionsPath(e){return path.join(e,...PHPXUI_INSTRUCTIONS_FILE.split("/"))}function escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function buildApplyTo(e){return[PHPXUI_CONFIG_FILE,e.project.hostFrameworkConfigFile,e.project.instructionsFile,`${e.project.componentsDirectory}/**`,e.tailwind.css].join(", ")}function buildInstructionScaffold(e){return["---",'description: "Use when working with PHPXUI, PHPXUI CLI-managed Prisma PHP components, phpxui.json manifest metadata, component installation, component updates, or generated component imports."','name: "PHPXUI AI Context"',`applyTo: "${buildApplyTo(e)}"`,"---","","# PHPXUI Instructions","","Keep PHPXUI-specific AI guidance here instead of in `.github/copilot-instructions.md` or `AGENTS.md`.","",`- Use \`${PHPXUI_CONFIG_FILE}\` under the \`${PHPXUI_MANIFEST_KEY}\` key as the source of truth for installed component inventory, configured paths, and registry metadata.`,"- Prefer `phpxui add ...` or `phpxui update` for registry-backed components instead of hand-writing generated PHPXUI classes.",`- Preserve manual content outside the managed PHPXUI block because refreshes replace only the \`${START_MARKER}\` ... \`${END_MARKER}\` section.`].join("\n")}function getPhpUsageExample(e){return["```php","<?php","",`use ${e}\\Alert;`,"","?>","","<Alert>"," <div>Saved changes</div>","</Alert>","```"].join("\n")}function getCatalogResponseExample(){return["```json","{",' "name": "Button",',' "content": "<?php\\n\\nnamespace Lib\\\\PHPXUI;\\n\\nuse PP\\\\PHPX\\\\PHPX;\\nuse Lib\\\\PHPXUI\\\\Slot;\\n\\nclass Button extends PHPX\\n{\\n ...generated PHP source...\\n}"',"}","```"].join("\n")}function buildManagedBlockContent(e){const n=e.components.length>0?e.components.map(e=>`- ${e.name}: \`${e.file}\``):["- No PHPXUI components are installed yet."];return["# PHPXUI AI Context","","This project uses `phpxui` to generate reusable PHPXUI components for Prisma PHP.","",`- Host framework: ${e.project.hostFramework}`,`- Prisma PHP root config: ${e.project.hostFrameworkConfigFile}`,`- PHPXUI instructions file: ${e.project.instructionsFile}`,`- Components directory: ${e.project.componentsDirectory}`,`- Installed component count: ${e.components.length}`,`- Component namespace: ${e.usage.entry}`,`- Tailwind CSS file: ${e.tailwind.css}`,`- Installed component inventory and project metadata: \`${PHPXUI_CONFIG_FILE}\` (under \`${PHPXUI_MANIFEST_KEY}\`)`,"","## Installing Components","","When a requested UI component does not exist yet, install it with `phpxui` instead of hand-writing generated PHPXUI classes.","",`- Add one component: \`${e.commands.addOne}\``,`- Add multiple components: \`${e.commands.addMany}\``,`- Add the full catalogue: \`${e.commands.addAll}\``,`- Refresh installed components: \`${e.commands.updateInstalled}\``,"","## Discovering Available Components","","Use the PHPXUI catalogue API to find component names before installing them.","",`- Fetch all available components: \`${e.catalogApi.listAll.method} ${e.catalogApi.listAll.url}\``,`- Fetch one component by name: \`${e.catalogApi.getOne.method} ${e.catalogApi.getOne.exampleUrl}\``,"- The `component=all` endpoint returns a JSON array of component objects.","- The single-component endpoint returns one JSON object with `name` and `content` fields.","","Single component response example:","",getCatalogResponseExample(),"","## Installed Components","",...n,"","## Using Installed Components","",`Import generated components from the \`${e.usage.entry}\` namespace and render them as PHPX tags.`,"",getPhpUsageExample(e.usage.entry),"","## Notes","",`- Reuse installed components from \`${PHPXUI_CONFIG_FILE}\` before generating new ones.`,`- Generated component files follow this pattern: \`${e.usage.filePattern}\``,"- Manual content outside this managed block is preserved."].join("\n")}function mergeManagedBlock(e,n){const t=e.replace(/\r\n/g,"\n"),o=new RegExp(`(^|\\n)[ \\t]*${escapeRegExp(START_MARKER)}[ \\t]*\\n[\\s\\S]*?\\n[ \\t]*${escapeRegExp(END_MARKER)}[ \\t]*(?=\\n|$)`);return o.test(t)?t.replace(o,(e,t)=>`${t}${n}`).trimEnd()+"\n":0===t.trim().length?`${n}\n`:`${t.trimEnd()}\n\n${n}\n`}async function writePhpXUIInstructionFile(e,n){const t=[START_MARKER,buildManagedBlockContent(e),END_MARKER].join("\n");await fs.ensureDir(path.dirname(n));const o=await fs.pathExists(n)?await fs.readFile(n,"utf8"):null,s=null===o||0===o.trim().length?`${buildInstructionScaffold(e)}\n\n${t}\n`:mergeManagedBlock(o,t);return await fs.writeFile(n,s,"utf8"),n}async function writePhpXUIWorkspaceInstructions(e,n){return writePhpXUIInstructionFile(e,getPhpXUIInstructionsPath(n))}export async function writePhpXUIInstructions(e){return writePhpXUIWorkspaceInstructions(await buildPhpXUIManifest(e),e.projectRoot)}export async function writePhpXUICopilotInstructions(e){return writePhpXUIInstructions(e)}export async function writePhpXUIAgentsInstructions(e){return writePhpXUIInstructions(e)}export async function refreshPhpXUIProjectContext(e){const n=await buildPhpXUIManifest(e),t=await writePhpXUIManifestToConfig({projectRoot:e.projectRoot,config:e.config,manifest:n});return await writePhpXUIWorkspaceInstructions(n,e.projectRoot),t}
|