phpxui 0.1.4 → 0.1.5
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/README.md +31 -17
- package/dist/cli.js +1 -0
- package/dist/commands/icons.js +1 -1
- package/dist/generators/php-component.js +1 -1
- package/dist/generators/php-components-bulk.js +1 -1
- package/dist/generators/phpxui-component-payload.js +1 -0
- package/dist/generators/write-component.js +1 -1
- package/dist/index.js +1 -1
- package/dist/utils/load-config.js +1 -1
- package/dist/utils/phpxui-ai-context.js +1 -0
- package/dist/utils/phpxui-manifest.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,15 +7,18 @@
|
|
|
7
7
|
|
|
8
8
|
## ✨ Features
|
|
9
9
|
|
|
10
|
-
| Feature | Details
|
|
11
|
-
| ---------------------- |
|
|
12
|
-
| **Bulk install** | `--all` downloads every component in one shot.
|
|
13
|
-
| **Update in place** | `update` scans your `outputDir` and re‑downloads every installed component (overwrite).
|
|
14
|
-
| **Ready‑to‑use code** | Each file already contains the `$class` merge logic and `{$attributes}` placeholder for **Wave** reactivity.
|
|
15
|
-
| **Clean paths** | Files are written under `src/Lib/PHPXUI/FancyName.php` with OS‑agnostic separators.
|
|
16
|
-
| **Friendly output** | Clear green / red summary with relative paths only.
|
|
17
|
-
| **
|
|
18
|
-
| **Tailwind bootstrap** | Ensures `tw-animate-css` and (on first run / missing file) writes `src/app/globals.css` for a sensible baseline.
|
|
10
|
+
| Feature | Details |
|
|
11
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
|
12
|
+
| **Bulk install** | `--all` downloads every component in one shot. |
|
|
13
|
+
| **Update in place** | `update` scans your `outputDir` and re‑downloads every installed component (overwrite). |
|
|
14
|
+
| **Ready‑to‑use code** | Each file already contains the `$class` merge logic and `{$attributes}` placeholder for **Wave** reactivity. |
|
|
15
|
+
| **Clean paths** | Files are written under `src/Lib/PHPXUI/FancyName.php` with OS‑agnostic separators. |
|
|
16
|
+
| **Friendly output** | Clear green / red summary with relative paths only. |
|
|
17
|
+
| **PPIcons bootstrap** | `add` and `update` install the required baseline `ppicons` set automatically, and still install any extra icons detected in generated files. |
|
|
18
|
+
| **Tailwind bootstrap** | Ensures `tw-animate-css` and (on first run / missing file) writes `src/app/globals.css` for a sensible baseline. |
|
|
19
|
+
| **AI project context** | Refreshes the `manifest` block inside `phpxui.json` and managed `AGENTS.md` / `.github/copilot-instructions.md` blocks after changes. |
|
|
20
|
+
|
|
21
|
+
`phpxui.json` is the CLI's own config file. In a Prisma PHP app, the framework config remains the root `prisma-php.json` file.
|
|
19
22
|
|
|
20
23
|
---
|
|
21
24
|
|
|
@@ -49,10 +52,6 @@ npx phpxui add --all
|
|
|
49
52
|
CLI output example:
|
|
50
53
|
|
|
51
54
|
```bash
|
|
52
|
-
📦 Installing ppicons CLI…
|
|
53
|
-
✨ Installing default icons: x chevron-down chevron-right
|
|
54
|
-
✔ Icons installed in src/Lib/PPIcons
|
|
55
|
-
|
|
56
55
|
✔ Alert → src/Lib/PHPXUI/Alert.php
|
|
57
56
|
✔ Dialog → src/Lib/PHPXUI/Dialog.php
|
|
58
57
|
✔ Badge → src/Lib/PHPXUI/Badge.php
|
|
@@ -137,7 +136,7 @@ phpxui <command> [--all] [--force] <component…>
|
|
|
137
136
|
| `--all` | Download the full catalogue in one request. Applies to `add`. |
|
|
138
137
|
| `--force` | Overwrite existing files. Applies to `add`. |
|
|
139
138
|
|
|
140
|
-
> **Note:**
|
|
139
|
+
> **Note:** `phpxui` installs the required baseline `ppicons` automatically. Install any extra icons separately with `npx ppicons add <icon-name>`.
|
|
141
140
|
|
|
142
141
|
---
|
|
143
142
|
|
|
@@ -147,15 +146,16 @@ On first run, **phpxui‑cli** creates a `phpxui.json` in your project root. The
|
|
|
147
146
|
|
|
148
147
|
- `outputDir`: where PHPXUI components are written (default: `src/Lib/PHPXUI`)
|
|
149
148
|
- `psr4`: mapping hints for components and icons
|
|
150
|
-
- `iconsInstalled`: internal flag to avoid reinstalling the default icon set
|
|
151
149
|
- `tailwind.css`: where the base CSS should live (default: `src/app/globals.css`)
|
|
150
|
+
- `manifest`: auto-generated AI metadata and installed component inventory maintained by the CLI
|
|
151
|
+
|
|
152
|
+
This file is separate from the Prisma PHP framework config in `prisma-php.json` at the project root.
|
|
152
153
|
|
|
153
154
|
Example:
|
|
154
155
|
|
|
155
156
|
```json
|
|
156
157
|
{
|
|
157
158
|
"outputDir": "src/Lib/PHPXUI",
|
|
158
|
-
"iconsInstalled": false,
|
|
159
159
|
"tailwind": {
|
|
160
160
|
"css": "src/app/globals.css",
|
|
161
161
|
"baseColor": "neutral",
|
|
@@ -172,8 +172,22 @@ Example:
|
|
|
172
172
|
|
|
173
173
|
---
|
|
174
174
|
|
|
175
|
+
## 🤖 AI Context
|
|
176
|
+
|
|
177
|
+
After `add` or `update`, **phpxui-cli** refreshes these files in your project root:
|
|
178
|
+
|
|
179
|
+
- `phpxui.json` (updates the `manifest` section)
|
|
180
|
+
- `AGENTS.md`
|
|
181
|
+
- `.github/copilot-instructions.md`
|
|
182
|
+
|
|
183
|
+
The markdown files receive a managed `phpxui` block that inventories installed components, records the component catalogue endpoints, and preserves any manual content outside that block.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
175
187
|
## 🎨 Using Additional Icons
|
|
176
188
|
|
|
189
|
+
`phpxui add ...` and `phpxui update` already install the baseline icon set used across PHPXUI components.
|
|
190
|
+
|
|
177
191
|
Need more icons? Use the **PPIcons** CLI directly:
|
|
178
192
|
|
|
179
193
|
```bash
|
|
@@ -187,7 +201,7 @@ Browse the complete icon catalogue and usage docs at **https://ppicons.tsnc.tech
|
|
|
187
201
|
|
|
188
202
|
## 📚 Documentation
|
|
189
203
|
|
|
190
|
-
Full guides and examples live at the PHPXUI documentation site:
|
|
204
|
+
Full guides and examples live at the PHPXUI documentation site: [https://phpxui.tsnc.tech/](https://phpxui.tsnc.tech/)
|
|
191
205
|
|
|
192
206
|
---
|
|
193
207
|
|
package/dist/cli.js
ADDED
|
@@ -0,0 +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:p}=t.loadPhpXUIConfig();t.ensurePackageInstalled("tw-animate-css");if(t.copyTailwindCss(p)){const e=path.relative(l,"src/app/globals.css").replace(/\\/g,"/");t.logger.log(chalk.green(p?`✔ Installed base Tailwind CSS → ${e}`:`✔ Added Tailwind CSS (missing) → ${e}`))}const i=path.resolve(l,c.outputDir||"src/Lib/PHPXUI"),g=()=>t.refreshAiContext({projectRoot:l,targetDir:i,config:c}),m=async e=>{if(0===e.length)return;const o=await t.collectComponentIcons(e,l);await t.installIcons(o)};try{if("update"===n){t.logger.log(chalk.blue(`🔎 Scanning for installed components in ${c.outputDir}...`));const e=t.getInstalledComponents(i);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,i,!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=p||s.force;if(s.all){const{ok:o,fail:n}=await t.generateAllComponents(i,e);return await m(o),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(p&&!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,i,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),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";
|
|
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(o){const n=[],e=new Set;for(const c of[...REQUIRED_PHPXUI_ICONS,...o]){const o=c.trim().toLowerCase();o&&!e.has(o)&&(e.add(o),n.push(o))}return n}export async function installIcons(o){const n=resolvePhpXUIIcons(o);try{console.log(chalk.blue("📦 Installing ppicons CLI...")),execSync("npm install -g ppicons",{stdio:"inherit"});const o=n.join(" ");console.log(chalk.blue(`✨ Installing required icons: ${o}`)),execSync(`npx ppicons add ${o}`,{stdio:"inherit"}),console.log(chalk.green("✔ Icons installed in src/Lib/PPIcons"))}catch(o){console.error(chalk.red("✖ Failed to install icons:"),o.message),process.exit(1)}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import fetch from"node-fetch";import{writeComponent}from"./write-component.js";import path from"path";const SINGLE_URL="https://phpxui.tsnc.tech/cli";export async function generateComponent(t,
|
|
1
|
+
import fetch from"node-fetch";import{writeComponent}from"./write-component.js";import{parsePhpXUIComponentPayload}from"./phpxui-component-payload.js";import path from"path";const SINGLE_URL="https://phpxui.tsnc.tech/cli";export async function generateComponent(o,t,n=!1){const e=`${SINGLE_URL}?component=${encodeURIComponent(o)}`,p=await fetch(e);if(!p.ok)throw new Error(`Could not fetch "${o}": ${p.status} – ${e}`);const r=parsePhpXUIComponentPayload(await p.json(),`Component "${o}"`),a=await writeComponent(r,t,n);return[path.relative(process.cwd(),a)]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import fetch from"node-fetch";import{writeComponent}from"./write-component.js";const BULK_URL="https://phpxui.tsnc.tech/cli?component=all";export async function generateAllComponents(t,
|
|
1
|
+
import fetch from"node-fetch";import{parsePhpXUIComponentList}from"./phpxui-component-payload.js";import{writeComponent}from"./write-component.js";const BULK_URL="https://phpxui.tsnc.tech/cli?component=all";export async function generateAllComponents(t,o=!1){const e=await fetch(BULK_URL);if(!e.ok)throw new Error(`Could not fetch component list: ${e.status} – ${BULK_URL}`);const n=parsePhpXUIComponentList(await e.json(),"PHPXUI component catalog");console.log(`➡ Received ${n.length} components. Generating…`);const s=[],p=[];let c=[];for(const e of n){const n=writeComponent(e,t,o).then(t=>{s.push(t)}).catch(t=>{p.push(`${e.name}: ${t.message}`)});c.push(n),c.length>=10&&(await Promise.allSettled(c),c=[])}return await Promise.allSettled(c),{ok:s,fail:p}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const COMPONENT_NAME_PATTERN=/^[A-Za-z][A-Za-z0-9]*$/;function isRecord(n){return"object"==typeof n&&null!==n&&!Array.isArray(n)}export function normalizePhpXUIComponentName(n){const r=n.trim();if(!COMPONENT_NAME_PATTERN.test(r))throw new Error(`Invalid component name "${n}" returned by API.`);return r}export function parsePhpXUIComponentPayload(n,r){if(!isRecord(n))throw new Error(`${r} returned an invalid component payload.`);if("string"!=typeof n.name)throw new Error(`${r} returned an invalid component name.`);if("string"!=typeof n.content)throw new Error(`${r} returned invalid component content.`);return{name:normalizePhpXUIComponentName(n.name),content:n.content}}export function parsePhpXUIComponentList(n,r){if(!Array.isArray(n))throw new Error(`${r} returned an invalid component list.`);return n.map((n,e)=>parsePhpXUIComponentPayload(n,`${r} item ${e+1}`))}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import fs from"fs-extra";import path from"path";export async function writeComponent(t,
|
|
1
|
+
import fs from"fs-extra";import path from"path";import{normalizePhpXUIComponentName}from"./phpxui-component-payload.js";export async function writeComponent(t,e,o=!1){const a=normalizePhpXUIComponentName(t.name),r=path.resolve(e),p=path.resolve(r,`${a}.php`),n=path.relative(r,p);if(n.startsWith("..")||path.isAbsolute(n))throw new Error(`Resolved component path escaped target directory for "${a}".`);return!o&&await fs.pathExists(p)||(await fs.ensureDir(path.dirname(p)),await fs.writeFile(p,t.content,"utf8")),p}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
2
|
+
import{runCli}from"./cli.js";(async()=>{const s=await runCli(process.argv.slice(2));process.exit(s)})();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import fs from"fs";import path from"path";const defaultConfig={style:"new-york",force:!1,outputDir:"src/Lib/PHPXUI",
|
|
1
|
+
import fs from"fs";import path from"path";const defaultConfig={style:"new-york",force:!1,outputDir:"src/Lib/PHPXUI",tailwind:{css:"src/app/globals.css",baseColor:"neutral",cssVariables:!0,prefix:""}};function normalizePhpXUIConfig(i){return{style:i.style??defaultConfig.style,force:i.force??defaultConfig.force,outputDir:i.outputDir??defaultConfig.outputDir,tailwind:{...defaultConfig.tailwind,...i.tailwind},...void 0!==i.manifest?{manifest:i.manifest}:{}}}export function loadPhpXUIConfig(){const i=path.resolve("phpxui.json"),t=fs.existsSync(i);t||(fs.writeFileSync(i,JSON.stringify(defaultConfig,null,2)),console.log("📦 Created default phpxui.json"));const o=fs.readFileSync(i,"utf-8");return{config:normalizePhpXUIConfig(JSON.parse(o)),isFirstRun:!t}}export function savePhpXUIConfig(i){const t=path.resolve("phpxui.json");fs.writeFileSync(t,JSON.stringify(normalizePhpXUIConfig(i),null,2))}
|
|
@@ -0,0 +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(`${escapeRegExp(START_MARKER)}[\\s\\S]*?${escapeRegExp(END_MARKER)}`);return o.test(t)?t.replace(o,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}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import fs from"fs-extra";import path from"node:path";import{getInstalledComponents}from"./scan-installed.js";export const PHPXUI_CONFIG_FILE="phpxui.json";export const PHPXUI_MANIFEST_KEY="manifest";export const PRISMA_PHP_CONFIG_FILE="prisma-php.json";export const PHPXUI_INSTRUCTIONS_FILE=".github/instructions/phpxui.instructions.md";const LEGACY_PHPXUI_MANIFEST_FILE="phpxui-manifest.json";function toRelativePath(t,e){const n=path.relative(t,e).replace(/\\/g,"/");return n.length>0?n:"."}function toRelativeConfigPath(t,e,n){const o=e&&e.trim().length>0?e:n;return toRelativePath(t,path.isAbsolute(o)?o:path.resolve(t,o)).replace(/\/+$/,"")||n}function inferNamespaceFromRelativePath(t){const e=t.split("/").filter(Boolean).filter(t=>"."!==t&&".."!==t);return"src"===e[0]?.toLowerCase()&&e.shift(),e.join("\\")||"App"}function getCommands(){return{addOne:"npx phpxui add <component-name>",addMany:"npx phpxui add <component-a> <component-b>",addAll:"npx phpxui add --all",updateInstalled:"npx phpxui update"}}function getCatalogApi(){return{listAll:{method:"GET",url:"https://phpxui.tsnc.tech/cli?component=all",returns:"PhpXUIComponentRecord[]",purpose:"List all available PHPXUI components that can be installed."},getOne:{method:"GET",urlTemplate:"https://phpxui.tsnc.tech/cli?component=<component-name>",exampleUrl:"https://phpxui.tsnc.tech/cli?component=Button",returns:"PhpXUIComponentRecord",purpose:"Fetch one component by name before installing or refreshing it."},responseFields:{name:"string",content:"string"}}}function getUsage(t,e){const n=toRelativePath(t,e);return{componentType:"class",entryStyle:"namespace",entry:inferNamespaceFromRelativePath(n),filePattern:`${n}/<ComponentName>.php`,syntax:"PHPX component tags"}}async function collectInstalledComponents(t,e){return await fs.pathExists(e)?getInstalledComponents(e).sort((t,e)=>t.localeCompare(e)).map(n=>({name:n,file:toRelativePath(t,path.join(e,`${n}.php`))})):[]}async function readConfigDocument(t,e){const n=path.join(t,"phpxui.json");return await fs.pathExists(n)?fs.readJson(n):{...e}}async function removeLegacyManifestFile(t){const e=path.join(t,"phpxui-manifest.json");await fs.pathExists(e)&&await fs.remove(e)}export async function writePhpXUIManifestToConfig({projectRoot:t,config:e,manifest:n}){const o=path.join(t,"phpxui.json"),a=await readConfigDocument(t,e);return await fs.writeJson(o,{...a,[PHPXUI_MANIFEST_KEY]:n},{spaces:2}),await removeLegacyManifestFile(t),o}export async function writePhpXUIManifest({projectRoot:t,targetDir:e,config:n}){return writePhpXUIManifestToConfig({projectRoot:t,config:n,manifest:await buildPhpXUIManifest({projectRoot:t,targetDir:e,config:n})})}export async function buildPhpXUIManifest({projectRoot:t,targetDir:e,config:n}){const o=await collectInstalledComponents(t,e),a=toRelativePath(t,e),i=toRelativeConfigPath(t,n.tailwind?.css,"src/app/globals.css");return{schemaVersion:1,generatedAt:(new Date).toISOString(),project:{framework:"phpxui",hostFramework:"prisma-php",rootDirectory:".",sourceDirectory:"src",hostFrameworkConfigFile:"prisma-php.json",configFile:"phpxui.json",componentsDirectory:a,instructionsFile:PHPXUI_INSTRUCTIONS_FILE},commands:getCommands(),catalogApi:getCatalogApi(),usage:getUsage(t,e),tailwind:{css:i},components:o}}
|