@peripheries/engine 0.6.1 → 0.7.0
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/package.json +1 -1
- package/src/commands/build.mjs +3 -3
- package/src/commands/check-css-scope.mjs +2 -0
- package/src/commands/check-tokens.mjs +2 -0
- package/src/commands/check.mjs +2 -2
- package/src/commands/upload-bundle.mjs +1 -1
- package/src/harness/app.mjs +1 -1
- package/src/index.d.mts +4 -0
- package/src/lib/config.mjs +1 -1
- package/src/lib/layers.mjs +1 -0
- package/src/lib/run.mjs +1 -1
package/package.json
CHANGED
package/src/commands/build.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{spawnSync}from"node:child_process";import{existsSync}from"node:fs";import{createRequire}from"node:module";import{resolve}from"node:path";import{pathToFileURL}from"node:url";import{loadConfig}from"../lib/config.mjs";import{parseFlagValue}from"../lib/env.mjs";import{REPO_ROOT}from"../lib/root.mjs";import{runCommand}from"../lib/run.mjs";import{EXTERNALS}from"./externals.mjs";const argv=process.argv.slice(2);const only=parseFlagValue(argv,"lineage");const config=await loadConfig();const lineages=only?config.lineages.filter(l=>l.name===only):config.lineages;if(only&&lineages.length===0)throw new Error(`[build] --lineage ${only} is not in the config's lineages`);const fromRepo=createRequire(resolve(REPO_ROOT,"package.json"));const importFromRepo=name=>import(pathToFileURL(fromRepo.resolve(name)).href);function check(label,status){if(status!==0){console.error(`[build] ${label} failed (exit ${status}).`);process.exit(status??1)}}if(!argv.includes("--no-typecheck")&&existsSync(resolve(REPO_ROOT,"tsconfig.build.json"))){console.log("[build] typecheck: tsc -p tsconfig.build.json --noEmit");const tsc=fromRepo.resolve("typescript/bin/tsc");check("typecheck",spawnSync(process.execPath,[tsc,"-p","tsconfig.build.json","--noEmit"],{cwd:REPO_ROOT,stdio:"inherit"}).status)}process.env.NODE_ENV="production";const{build}=await importFromRepo("vite");const react=(await importFromRepo("@vitejs/plugin-react")).default;for(const lineage of lineages){const entry=resolve(REPO_ROOT,lineage.entry);if(!existsSync(entry))throw new Error(`[build] no barrel at ${lineage.entry} for lineage "${lineage.name}"`);const external=[...new Set([...EXTERNALS,...config.shared,...lineage.shared??[]])].filter(s=>s!==lineage.specifier);console.log(`
|
|
3
|
-
[build] ${lineage.name}: ${lineage.entry} \u2192 ${lineage.dist}/index.js`);await build({configFile:false,mode:"production",root:REPO_ROOT,logLevel:"warn",plugins:[react()],define:{"process.env.NODE_ENV":JSON.stringify("production"),__OA_BUNDLE_NAME__:JSON.stringify(config.org)},resolve:{alias:{"@":resolve(REPO_ROOT,"src")}},optimizeDeps:{exclude:external},build:{lib:{entry,formats:["es"],fileName:()=>"index.js"},rollupOptions:{external},outDir:resolve(REPO_ROOT,lineage.dist),emptyOutDir:true,sourcemap:true}});check(`${lineage.name} contracts`,runCommand("contracts",["--entry",lineage.entry,"--out",`${lineage.dist}/contracts.json`]));check(`${lineage.name} knowledge`,runCommand("knowledge",["--bundle",lineage.name]))}console.log(`
|
|
4
|
-
[build] \u2705 ${lineages.map(l=>l.name).join(", ")}`);
|
|
2
|
+
import{spawnSync}from"node:child_process";import{existsSync,readdirSync,readFileSync,rmSync,writeFileSync}from"node:fs";import{createRequire}from"node:module";import{resolve}from"node:path";import{pathToFileURL}from"node:url";import{loadConfig}from"../lib/config.mjs";import{parseFlagValue}from"../lib/env.mjs";import{layerCss,layerFor}from"../lib/layers.mjs";import{REPO_ROOT}from"../lib/root.mjs";import{runCommand}from"../lib/run.mjs";import{EXTERNALS}from"./externals.mjs";const argv=process.argv.slice(2);const only=parseFlagValue(argv,"lineage");const config=await loadConfig();const lineages=only?config.lineages.filter(l=>l.name===only):config.lineages;if(only&&lineages.length===0)throw new Error(`[build] --lineage ${only} is not in the config's lineages`);const fromRepo=createRequire(resolve(REPO_ROOT,"package.json"));const importFromRepo=name=>import(pathToFileURL(fromRepo.resolve(name)).href);function check(label,status){if(status!==0){console.error(`[build] ${label} failed (exit ${status}).`);process.exit(status??1)}}if(!argv.includes("--no-typecheck")&&existsSync(resolve(REPO_ROOT,"tsconfig.build.json"))){console.log("[build] typecheck: tsc -p tsconfig.build.json --noEmit");const tsc=fromRepo.resolve("typescript/bin/tsc");check("typecheck",spawnSync(process.execPath,[tsc,"-p","tsconfig.build.json","--noEmit"],{cwd:REPO_ROOT,stdio:"inherit"}).status)}process.env.NODE_ENV="production";const{build}=await importFromRepo("vite");const react=(await importFromRepo("@vitejs/plugin-react")).default;for(const lineage of lineages){const entry=resolve(REPO_ROOT,lineage.entry);if(!existsSync(entry))throw new Error(`[build] no barrel at ${lineage.entry} for lineage "${lineage.name}"`);const external=[...new Set([...EXTERNALS,...config.shared,...lineage.shared??[]])].filter(s=>s!==lineage.specifier);console.log(`
|
|
3
|
+
[build] ${lineage.name}: ${lineage.entry} \u2192 ${lineage.dist}/index.js`);await build({configFile:false,mode:"production",root:REPO_ROOT,logLevel:"warn",plugins:[react()],define:{"process.env.NODE_ENV":JSON.stringify("production"),__OA_BUNDLE_NAME__:JSON.stringify(config.org)},resolve:{alias:{"@":resolve(REPO_ROOT,"src")}},optimizeDeps:{exclude:external},build:{lib:{entry,formats:["es"],fileName:()=>"index.js"},rollupOptions:{external},outDir:resolve(REPO_ROOT,lineage.dist),emptyOutDir:true,sourcemap:true}});await writeLayeredCss(lineage);check(`${lineage.name} contracts`,runCommand("contracts",["--entry",lineage.entry,"--out",`${lineage.dist}/contracts.json`]));check(`${lineage.name} knowledge`,runCommand("knowledge",["--bundle",lineage.name]))}console.log(`
|
|
4
|
+
[build] \u2705 ${lineages.map(l=>l.name).join(", ")}`);async function writeLayeredCss(lineage){const dist=resolve(REPO_ROOT,lineage.dist);const files=readdirSync(dist).filter(f=>f.endsWith(".css"));if(files.length===0)return;const css=files.map(f=>readFileSync(resolve(dist,f),"utf8")).join("\n");for(const f of files)rmSync(resolve(dist,f));const postcss=(await importFromRepo("postcss")).default;const layer=layerFor(lineage);writeFileSync(resolve(dist,"index.css"),layerCss(postcss,css,layer));console.log(`[build] ${lineage.name}: index.css in @layer ${layer}`)}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{existsSync,readdirSync,readFileSync,statSync}from"node:fs";import{createRequire}from"node:module";import{join,relative,resolve}from"node:path";import{pathToFileURL}from"node:url";import{loadConfig}from"../lib/config.mjs";import{REPO_ROOT}from"../lib/root.mjs";const strict=process.argv.includes("--strict");const{org,lineages}=await loadConfig();const prefixes=[...new Set(lineages.map(l=>l.cssPrefix??(l.kind==="shared"?`${l.name}-`:`${org}-`)))];const SKIP=/(^|\/)(node_modules|__output__|dist[^/]*)(\/|$)/;const walk=p=>{if(!existsSync(p)||SKIP.test(p))return[];return statSync(p).isDirectory()?readdirSync(p).flatMap(n=>walk(join(p,n))):[p]};const files=walk(resolve(REPO_ROOT,"src")).filter(f=>f.endsWith(".css"));const fromRepo=createRequire(resolve(REPO_ROOT,"package.json"));const postcss=files.length?(await import(pathToFileURL(fromRepo.resolve("postcss")).href)).default:null;const exempt=node=>{for(let p=node.parent;p;p=p.parent){if(p.type==="atrule"&&(/keyframes$/.test(p.name)||p.name==="font-face"||p.name==="layer"&&p.params.trim()==="tokens"))return true}return false};const scoped=selector=>prefixes.some(pre=>new RegExp(`\\.${pre.replace(/[-]/g,"\\-")}[\\w-]`).test(selector));const findings=[];for(const file of files){const root=postcss.parse(readFileSync(file,"utf8"),{from:file});root.walkRules(rule=>{if(exempt(rule))return;for(const selector of rule.selectors){if(!scoped(selector))findings.push(`${relative(REPO_ROOT,file)}:${rule.source?.start?.line??"?"}: "${selector}" is not under ${prefixes.map(p=>`.${p}*`).join(" or ")}`)}})}const shown=strict||process.argv.includes("--all")?findings:findings.slice(0,20);for(const f of shown)console[strict?"error":"warn"](`[css-scope] ${f}`);if(shown.length<findings.length)console.warn(`[css-scope] \u2026 ${findings.length-shown.length} more (--all lists them)`);console.log(`[css-scope] ${files.length} stylesheet(s), prefixes ${prefixes.join(", ")}; ${findings.length} finding(s)${findings.length&&!strict?" (warnings: --strict fails on them)":""}.`);process.exit(strict&&findings.length?1:0);
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{existsSync,readdirSync,readFileSync,statSync}from"node:fs";import{join,relative,resolve}from"node:path";import{REPO_ROOT}from"../lib/root.mjs";const strict=process.argv.includes("--strict");const SKIP=/(^|\/)(node_modules|__output__|dist[^/]*)(\/|$)|\.(fixtures|test|stories)\.[jt]sx?$|\.d\.ts$/;const RULES=[[/var\(\s*--palette-[\w-]+/,"a primitive token (read a semantic one)"],[/var\(\s*--oa-[\w-]+/,"a legacy --oa-* name"],[/(?<![\w-])#[0-9a-fA-F]{3,8}\b(?![\w-])/,"a hex colour (use a token)"],[/\b(rgba?|hsla?|oklch|oklab)\(\s*\d/,"a literal colour (use a token)"]];const walk=p=>{if(!existsSync(p)||SKIP.test(p))return[];return statSync(p).isDirectory()?readdirSync(p).flatMap(n=>walk(join(p,n))):[p]};const files=walk(resolve(REPO_ROOT,"src")).filter(f=>/\.(css|tsx?|mts)$/.test(f));const findings=[];for(const file of files){const lines=readFileSync(file,"utf8").split("\n");if(lines.slice(0,15).some(l=>l.includes("check-tokens: defines tokens")))continue;const css=file.endsWith(".css");lines.forEach((line,i)=>{const trimmed=line.trim();if(trimmed.startsWith("//")||trimmed.startsWith("*")||trimmed.startsWith("/*"))return;for(const[re,what]of RULES){if(!css&&re.source.startsWith("(?<!")&&!/['"`][^'"`]*#[0-9a-fA-F]{3,8}\b/.test(line))continue;const m=line.match(re);if(m)findings.push(`${relative(REPO_ROOT,file)}:${i+1}: ${what}: ${m[0]}`)}})}const shown=strict||process.argv.includes("--all")?findings:findings.slice(0,20);for(const f of shown)console[strict?"error":"warn"](`[tokens] ${f}`);if(shown.length<findings.length)console.warn(`[tokens] \u2026 ${findings.length-shown.length} more (--all lists them)`);console.log(`[tokens] ${files.length} file(s), ${findings.length} finding(s)${findings.length&&!strict?" (warnings: --strict fails on them)":""}.`);process.exit(strict&&findings.length?1:0);
|
package/src/commands/check.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import{loadConfig}from"../lib/config.mjs";import{runCommand}from"../lib/run.mjs";const{lineages,checks}=await loadConfig();const named=process.argv.slice(2).filter(a=>!a.startsWith("--"));const list=named.length?named:checks.run;const results=[];for(const name of list){if(name==="knowledge"){for(const l of lineages){console.log(`
|
|
3
|
-
[check] knowledge --bundle ${l.name}`);results.push([`knowledge (${l.name})`,runCommand("knowledge",["--bundle",l.name,"--check"])])}continue}console.log(`
|
|
4
|
-
[check] ${name}`);results.push([name,runCommand(
|
|
3
|
+
[check] knowledge --bundle ${l.name}`);results.push([`knowledge (${l.name})`,runCommand("knowledge",["--bundle",l.name,"--check"])])}continue}const[command,...args]=name.split(/\s+/);console.log(`
|
|
4
|
+
[check] ${name}`);results.push([name,runCommand(command,args)])}const failed=results.filter(([,status])=>status!==0);console.log(`
|
|
5
5
|
[check] ${results.length-failed.length}/${results.length} passed${failed.length?`; failed: ${failed.map(([n])=>n).join(", ")}`:""}.`);process.exit(failed.length?1:0);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{readFileSync,existsSync,statSync}from"node:fs";import{resolve,dirname}from"node:path";import{fileURLToPath}from"node:url";import{BUNDLE_BUCKET,PUBLIC_BUNDLE_BUCKET,initFromArgv,parseFlagValue}from"../lib/env.mjs";import{REPO_ROOT as REPO_ROOT_}from"../lib/root.mjs";import{lineageConfig}from"../lib/config.mjs";const argv=process.argv.slice(2);const{target,orgSlug:ORG_SLUG,supabase}=initFromArgv(argv);const BUNDLE_NAME=parseFlagValue(argv,"bundle")??"main";const dryRun=argv.includes("--dry-run");const IS_MAIN=BUNDLE_NAME==="main";const IS_PUBLIC=BUNDLE_NAME==="public";const IS_ORG_WIDE=IS_MAIN||IS_PUBLIC;const IS_SHARED=(await lineageConfig(BUNDLE_NAME)).kind==="shared";const DEFAULT_BUCKET=IS_PUBLIC||IS_SHARED?PUBLIC_BUNDLE_BUCKET:BUNDLE_BUCKET;const STORAGE_BUCKET=process.env.STORAGE_BUCKET||DEFAULT_BUCKET;if(STORAGE_BUCKET!==DEFAULT_BUCKET){console.error(`[upload-bundle] STORAGE_BUCKET must be "${DEFAULT_BUCKET}" for lineage "${BUNDLE_NAME}", got "${STORAGE_BUCKET}".`);process.exit(2)}const VERSION=process.env.VERSION||`v_${target}_${new Date().toISOString().replace(/[-:T]/g,"").replace(/\..+$/,"").slice(0,14)}`;if(!process.env.VERSION){console.log(`[upload-bundle] VERSION auto-generated: ${VERSION}`);process.env.VERSION=VERSION}const distDir=resolve(REPO_ROOT_,(await lineageConfig(BUNDLE_NAME)).dist);const bundlePath=resolve(distDir,"index.js");if(!existsSync(bundlePath)){console.error(`[upload-bundle] ${bundlePath} does not exist. `+(IS_MAIN?"Did `npm run build` run?":`Did \`OA_PROJECT_BUNDLE=${BUNDLE_NAME} npm run build:bundle\` run?`));process.exit(1)}console.log(`[upload-bundle] lineage=${BUNDLE_NAME} dist=${distDir.split("/").slice(-2).join("/")}`);const{data:orgRow,error:orgError}=await supabase.from("organization").select("id").eq("metadata->>org_slug",ORG_SLUG).maybeSingle();if(orgError||!orgRow?.id){console.error(`[upload-bundle] Could not resolve org_id for org_slug="${ORG_SLUG}":`,orgError??"no matching organization row");process.exit(1)}const ORG_ID=orgRow.id;async function uploadOne(localPath,remotePath,contentType){const body=readFileSync(localPath);if(dryRun){console.log(`[upload-bundle] would upload ${STORAGE_BUCKET}/${remotePath} (${body.byteLength} bytes)`);return}const{error}=await supabase.storage.from(STORAGE_BUCKET).upload(remotePath,body,{contentType,upsert:false});if(error){console.error(`[upload-bundle] Failed to upload ${remotePath}:`,error);process.exit(1)}console.log(`[upload-bundle] \u2191 ${remotePath} (${body.byteLength} bytes)`)}const remoteBase=IS_ORG_WIDE?`${ORG_SLUG}/${VERSION}`:`${ORG_SLUG}/${BUNDLE_NAME}/${VERSION}`;await uploadOne(bundlePath,`${remoteBase}/index.js`,"application/javascript");const mapPath=resolve(distDir,"index.js.map");if(existsSync(mapPath)){await uploadOne(mapPath,`${remoteBase}/index.js.map`,"application/json")}const contractsPath=resolve(distDir,"contracts.json");if(existsSync(contractsPath)){await uploadOne(contractsPath,`${remoteBase}/contracts.json`,"application/json")}const{data:existingBundle,error:existingBundleError}=await supabase.from("component_bundle").select("id, status").eq("org_id",ORG_ID).eq("bundle_name",BUNDLE_NAME).eq("version",VERSION).maybeSingle();if(existingBundleError){console.error(`[upload-bundle] Failed to look up existing component_bundle for (org=${ORG_SLUG}, bundle=${BUNDLE_NAME}, version=${VERSION}):`,existingBundleError);process.exit(1)}const bundleBytes=statSync(bundlePath).size;const hasSourcemap=existsSync(mapPath);const bundlePayload={org_id:ORG_ID,org_slug:ORG_SLUG,bundle_name:BUNDLE_NAME,version:VERSION,status:"uploaded",storage_bucket:STORAGE_BUCKET,storage_path:`${remoteBase}/index.js`,...IS_SHARED?{is_public:true}:{},uploaded_at:new Date().toISOString(),registered_at:null,cutover_at:null,git_sha:process.env.DEPLOY_SHA??process.env.GITHUB_SHA??null,git_ref:process.env.DEPLOY_REF??process.env.GITHUB_REF??null,git_repo:process.env.GITHUB_REPOSITORY??null,process_id:process.env.PROCESS_ID||null,metadata:{bundle_bytes:bundleBytes,has_sourcemap:hasSourcemap,bundle_scope:BUNDLE_NAME,...process.env.GITHUB_RUN_ID?{github_run_id:process.env.GITHUB_RUN_ID}:{},...process.env.GITHUB_RUN_ATTEMPT?{github_run_attempt:process.env.GITHUB_RUN_ATTEMPT}:{}}};if(dryRun){console.log(`[upload-bundle] dry-run \u2014 would ${existingBundle?.id?`UPDATE ${existingBundle.id}`:"INSERT"} component_bundle:`);console.log(JSON.stringify(bundlePayload,null,2));console.log("[upload-bundle] dry-run \u2014 nothing written.")}else if(existingBundle?.id){const{error:updateError}=await supabase.from("component_bundle").update(bundlePayload).eq("id",existingBundle.id);if(updateError){console.error(`[upload-bundle] Failed to update component_bundle row:`,updateError);process.exit(1)}console.log(`[upload-bundle] ~ component_bundle ${existingBundle.id} reset to status='uploaded' (was '${existingBundle.status}').`)}else{const{data:inserted,error:insertError}=await supabase.from("component_bundle").insert(bundlePayload).select("id").single();if(insertError){console.error(`[upload-bundle] Failed to insert component_bundle row:`,insertError);process.exit(1)}console.log(`[upload-bundle] + component_bundle ${inserted.id} created (status='uploaded').`)}console.log(`[upload-bundle] Done \u2014 target=${target} org=${ORG_SLUG} bundle=${BUNDLE_NAME} version=${VERSION}. Run register-components.mjs next.`);
|
|
2
|
+
import{readFileSync,existsSync,statSync}from"node:fs";import{resolve,dirname}from"node:path";import{fileURLToPath}from"node:url";import{BUNDLE_BUCKET,PUBLIC_BUNDLE_BUCKET,initFromArgv,parseFlagValue}from"../lib/env.mjs";import{REPO_ROOT as REPO_ROOT_}from"../lib/root.mjs";import{lineageConfig}from"../lib/config.mjs";const argv=process.argv.slice(2);const{target,orgSlug:ORG_SLUG,supabase}=initFromArgv(argv);const BUNDLE_NAME=parseFlagValue(argv,"bundle")??"main";const dryRun=argv.includes("--dry-run");const IS_MAIN=BUNDLE_NAME==="main";const IS_PUBLIC=BUNDLE_NAME==="public";const IS_ORG_WIDE=IS_MAIN||IS_PUBLIC;const IS_SHARED=(await lineageConfig(BUNDLE_NAME)).kind==="shared";const DEFAULT_BUCKET=IS_PUBLIC||IS_SHARED?PUBLIC_BUNDLE_BUCKET:BUNDLE_BUCKET;const STORAGE_BUCKET=process.env.STORAGE_BUCKET||DEFAULT_BUCKET;if(STORAGE_BUCKET!==DEFAULT_BUCKET){console.error(`[upload-bundle] STORAGE_BUCKET must be "${DEFAULT_BUCKET}" for lineage "${BUNDLE_NAME}", got "${STORAGE_BUCKET}".`);process.exit(2)}const VERSION=process.env.VERSION||`v_${target}_${new Date().toISOString().replace(/[-:T]/g,"").replace(/\..+$/,"").slice(0,14)}`;if(!process.env.VERSION){console.log(`[upload-bundle] VERSION auto-generated: ${VERSION}`);process.env.VERSION=VERSION}const distDir=resolve(REPO_ROOT_,(await lineageConfig(BUNDLE_NAME)).dist);const bundlePath=resolve(distDir,"index.js");if(!existsSync(bundlePath)){console.error(`[upload-bundle] ${bundlePath} does not exist. `+(IS_MAIN?"Did `npm run build` run?":`Did \`OA_PROJECT_BUNDLE=${BUNDLE_NAME} npm run build:bundle\` run?`));process.exit(1)}console.log(`[upload-bundle] lineage=${BUNDLE_NAME} dist=${distDir.split("/").slice(-2).join("/")}`);const{data:orgRow,error:orgError}=await supabase.from("organization").select("id").eq("metadata->>org_slug",ORG_SLUG).maybeSingle();if(orgError||!orgRow?.id){console.error(`[upload-bundle] Could not resolve org_id for org_slug="${ORG_SLUG}":`,orgError??"no matching organization row");process.exit(1)}const ORG_ID=orgRow.id;async function uploadOne(localPath,remotePath,contentType){const body=readFileSync(localPath);if(dryRun){console.log(`[upload-bundle] would upload ${STORAGE_BUCKET}/${remotePath} (${body.byteLength} bytes)`);return}const{error}=await supabase.storage.from(STORAGE_BUCKET).upload(remotePath,body,{contentType,upsert:false});if(error){console.error(`[upload-bundle] Failed to upload ${remotePath}:`,error);process.exit(1)}console.log(`[upload-bundle] \u2191 ${remotePath} (${body.byteLength} bytes)`)}const remoteBase=IS_ORG_WIDE?`${ORG_SLUG}/${VERSION}`:`${ORG_SLUG}/${BUNDLE_NAME}/${VERSION}`;await uploadOne(bundlePath,`${remoteBase}/index.js`,"application/javascript");const cssPath=resolve(distDir,"index.css");if(existsSync(cssPath)){await uploadOne(cssPath,`${remoteBase}/index.css`,"text/css")}const mapPath=resolve(distDir,"index.js.map");if(existsSync(mapPath)){await uploadOne(mapPath,`${remoteBase}/index.js.map`,"application/json")}const contractsPath=resolve(distDir,"contracts.json");if(existsSync(contractsPath)){await uploadOne(contractsPath,`${remoteBase}/contracts.json`,"application/json")}const{data:existingBundle,error:existingBundleError}=await supabase.from("component_bundle").select("id, status").eq("org_id",ORG_ID).eq("bundle_name",BUNDLE_NAME).eq("version",VERSION).maybeSingle();if(existingBundleError){console.error(`[upload-bundle] Failed to look up existing component_bundle for (org=${ORG_SLUG}, bundle=${BUNDLE_NAME}, version=${VERSION}):`,existingBundleError);process.exit(1)}const bundleBytes=statSync(bundlePath).size;const hasSourcemap=existsSync(mapPath);const bundlePayload={org_id:ORG_ID,org_slug:ORG_SLUG,bundle_name:BUNDLE_NAME,version:VERSION,status:"uploaded",storage_bucket:STORAGE_BUCKET,storage_path:`${remoteBase}/index.js`,...IS_SHARED?{is_public:true}:{},uploaded_at:new Date().toISOString(),registered_at:null,cutover_at:null,git_sha:process.env.DEPLOY_SHA??process.env.GITHUB_SHA??null,git_ref:process.env.DEPLOY_REF??process.env.GITHUB_REF??null,git_repo:process.env.GITHUB_REPOSITORY??null,process_id:process.env.PROCESS_ID||null,metadata:{bundle_bytes:bundleBytes,has_sourcemap:hasSourcemap,bundle_scope:BUNDLE_NAME,files:["index.js",...existsSync(cssPath)?["index.css"]:[]],...process.env.GITHUB_RUN_ID?{github_run_id:process.env.GITHUB_RUN_ID}:{},...process.env.GITHUB_RUN_ATTEMPT?{github_run_attempt:process.env.GITHUB_RUN_ATTEMPT}:{}}};if(dryRun){console.log(`[upload-bundle] dry-run \u2014 would ${existingBundle?.id?`UPDATE ${existingBundle.id}`:"INSERT"} component_bundle:`);console.log(JSON.stringify(bundlePayload,null,2));console.log("[upload-bundle] dry-run \u2014 nothing written.")}else if(existingBundle?.id){const{error:updateError}=await supabase.from("component_bundle").update(bundlePayload).eq("id",existingBundle.id);if(updateError){console.error(`[upload-bundle] Failed to update component_bundle row:`,updateError);process.exit(1)}console.log(`[upload-bundle] ~ component_bundle ${existingBundle.id} reset to status='uploaded' (was '${existingBundle.status}').`)}else{const{data:inserted,error:insertError}=await supabase.from("component_bundle").insert(bundlePayload).select("id").single();if(insertError){console.error(`[upload-bundle] Failed to insert component_bundle row:`,insertError);process.exit(1)}console.log(`[upload-bundle] + component_bundle ${inserted.id} created (status='uploaded').`)}console.log(`[upload-bundle] Done \u2014 target=${target} org=${ORG_SLUG} bundle=${BUNDLE_NAME} version=${VERSION}. Run register-components.mjs next.`);
|
package/src/harness/app.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import{Fragment,jsx,jsxs}from"react/jsx-runtime";import"@peripheries/renderer/styles.css";import{pageRuntimeFromValues,projectCellActions}from"@peripheries/renderer/core";import{PageRenderer}from"@peripheries/renderer/react";import{getStackStore}from"@peripheries/renderer/runtime";import{FIXTURE_BASE_PROPS}from"@peripheries/renderer/testing";import{Component,isValidElement,useEffect,useMemo}from"react";import{createRoot}from"react-dom/client";const fixtureName=path=>path.split("/").pop().replace(/\.fixtures\.tsx?$/,"");const pageKey=path=>{const m=path.match(/\/project_templates\/([^/]+)\/pages\/([^/]+)\/page\.json$/)??path.match(/\/pages\/([^/]+)\/page\.json$/);return m?m.slice(1).join("/"):path};function isJson(v){if(v===null||["string","number","boolean"].includes(typeof v))return true;if(Array.isArray(v))return v.every(isJson);if(typeof v!=="object"||isValidElement(v))return false;const proto=Object.getPrototypeOf(v);return(proto===Object.prototype||proto===null)&&Object.values(v).every(isJson)}class Boundary extends Component{state={error:null};static getDerivedStateFromError(error){return{error}}componentDidCatch(error,info){window.__ENGINE_HARNESS_ERROR=`${error.message}
|
|
2
|
-
${info.componentStack??""}`}render(){return this.state.error?jsx("pre",{role:"alert",children:this.state.error.message}):this.props.children}}function Ready({children}){useEffect(()=>{const id=requestAnimationFrame(()=>requestAnimationFrame(()=>window.__ENGINE_HARNESS_READY=true));return()=>cancelAnimationFrame(id)},[]);return jsx(Fragment,{children})}function RenderedPage({row,values,actions,baseProps,components,Wrapper,statusOverride}){const runtime=useMemo(()=>{const rt=pageRuntimeFromValues(row,{values});if(statusOverride&&(statusOverride.isLoading||statusOverride.error)){const error=statusOverride.error?new Error(statusOverride.error):null;for(const cell of rt.cells)rt.cellData[cell.id]??={static:{},declared:{}};for(const own of Object.values(rt.cellData)){const keys=Object.keys(own.static).length?Object.keys(own.static):["fixture"];for(const k of keys)own.static[k]={data:void 0,isLoading:Boolean(statusOverride.isLoading),error}}}return rt},[row,values,statusOverride]);const bundles=useMemo(()=>{const ThemeProvider=Wrapper?({children})=>jsx(Wrapper,{baseProps,children}):void 0;const bundle={id:"harness",label:"harness",components,contracts:{},...ThemeProvider?{ThemeProvider}:{}};return{scope:[bundle],forCell:()=>null}},[components,Wrapper,baseProps]);const environment=useMemo(()=>{const pageActions=Object.fromEntries(Object.keys(actions??{}).map(k=>[k,async input=>(console.info(`[harness] action ${k}`,input),{ok:true})]));window.__ENGINE_HARNESS_DIAGNOSTICS=[];return{core:{},navigate:()=>{},store:getStackStore(),actionsFor:cell=>cell.actions?projectCellActions(cell.actions,pageActions):Object.keys(pageActions).length?pageActions:void 0,onCellError:(cellId,error)=>console.error(`[harness] cell "${cellId}" failed:`,error),onDiagnostic:d=>{window.__ENGINE_HARNESS_DIAGNOSTICS.push({code:d.code,severity:d.severity,message:d.message,...d.cellId?{cellId:d.cellId}:{}});if(d.severity==="error")console.error(`[harness] ${d.code}: ${d.message}`)}}},[actions]);return jsx(PageRenderer,{runtime,bundles,params:{},baseProps,context:{environment:"harness"},environment})}function pageRow(id,json){return{id,name:json.name,org_id:null,project_id:null,process_id:null,graph_node_id:null,page_type:json.page_type??null,status:"published",is_template:json.is_template??false,content:json.content??{cells:[]},layout:json.layout??{type:"stack",gap:16},metadata:json.metadata??null}}function Index({fixtures,pages}){useEffect(()=>void(window.__ENGINE_HARNESS_READY=true),[]);const link=q=>`?${q}`;return jsxs("main",{style:{fontFamily:"system-ui, sans-serif",padding:24,maxWidth:960},children:[jsx("h1",{children:"Harness"}),jsx("h2",{children:"Fixtures"}),fixtures.map(([name,scenarios])=>jsxs("section",{children:[jsx("h3",{children:name}),jsx("ul",{children:scenarios.map(s=>jsxs("li",{children:[jsx("a",{href:link(`fixture=${encodeURIComponent(name)}&scenario=${encodeURIComponent(s.name)}`),children:s.name})," \xB7 ",jsx("a",{href:link(`fixture=${encodeURIComponent(name)}&scenario=${encodeURIComponent(s.name)}&container=320`),children:"in 320px"})]},s.name))})]},name)),jsx("h2",{children:"Pages"}),jsx("ul",{children:pages.map(p=>jsx("li",{children:jsx("a",{href:link(`page=${encodeURIComponent(p)}`),children:p})},p))})]})}function mountHarness(sources){const q=new URLSearchParams(window.location.search);const components=Object.assign({},...Object.values(sources.barrels));const fixtures=Object.entries(sources.fixtures).map(([path,mod])=>[fixtureName(path),[...mod.scenarios??[]]]).sort(([a],[b])=>a.localeCompare(b));const pages=Object.fromEntries(Object.entries(sources.pages).map(([path,json])=>[pageKey(path),{json,mock:sources.mocks[path.replace(/page\.json$/,"mock.json")]}]));let body;const fixture=q.get("fixture");const page=q.get("page");if(fixture){const scenario=fixtures.find(([n])=>n===fixture)?.[1].find(s=>s.name===q.get("scenario"));if(!scenario){window.__ENGINE_HARNESS_ERROR=`no scenario "${q.get("scenario")}" for ${fixture}`;body=null}else if(!isJson(scenario.props??{})){const Direct=components[fixture];if(!Direct)window.__ENGINE_HARNESS_ERROR=`${fixture} is not exported from any barrel`;const baseProps={...FIXTURE_BASE_PROPS,...scenario.baseProps};const element=Direct?jsx(Direct,{...scenario.props,baseProps}):null;body=sources.Wrapper?jsx(sources.Wrapper,{baseProps,children:element}):element}else{const cell={id:"fixture",component:fixture,props:scenario.props??{},...scenario.data?{data:{static:scenario.data}}:{},...scenario.selections?{selections:scenario.selections}:{},...scenario.viewState?{viewState:scenario.viewState}:{},...scenario.live?{live:scenario.live}:{}};body=jsx(RenderedPage,{row:pageRow(`${fixture}/${scenario.name}`,{name:`${fixture} \xB7 ${scenario.name}`,content:{cells:[cell]}}),values:{},actions:scenario.actions,baseProps:{...FIXTURE_BASE_PROPS,...scenario.baseProps},components,Wrapper:sources.Wrapper,statusOverride:scenario.status})}}else if(page){const entry=pages[page];if(!entry){window.__ENGINE_HARNESS_ERROR=`no page "${page}"`;body=null}else{const values={...entry.mock?.data};body=jsx(RenderedPage,{row:pageRow(page,entry.json),values,actions:entry.mock?.actions,baseProps:{...FIXTURE_BASE_PROPS,...entry.mock?.baseProps},components,Wrapper:sources.Wrapper})}}else{body=jsx(Index,{fixtures,pages:Object.keys(pages).sort()})}const container=Number(q.get("container"))||null;const framed=container?jsx("div",{"data-engine-container":"",style:{width:container,containerType:"inline-size",outline:"1px dashed #bbb"},children:body}):body;createRoot(document.getElementById("root")).render(jsx(Boundary,{children:jsx(Ready,{children:framed})}))}export{mountHarness};
|
|
2
|
+
${info.componentStack??""}`}render(){return this.state.error?jsx("pre",{role:"alert",children:this.state.error.message}):this.props.children}}function Ready({children}){useEffect(()=>{const id=requestAnimationFrame(()=>requestAnimationFrame(()=>window.__ENGINE_HARNESS_READY=true));return()=>cancelAnimationFrame(id)},[]);return jsx(Fragment,{children})}function RenderedPage({row,values,actions,baseProps,components,Wrapper,statusOverride}){const runtime=useMemo(()=>{const rt=pageRuntimeFromValues(row,{values});if(statusOverride&&(statusOverride.isLoading||statusOverride.error)){const error=statusOverride.error?new Error(statusOverride.error):null;for(const cell of rt.cells)rt.cellData[cell.id]??={static:{},declared:{}};for(const own of Object.values(rt.cellData)){const keys=Object.keys(own.static).length?Object.keys(own.static):["fixture"];for(const k of keys)own.static[k]={data:void 0,isLoading:Boolean(statusOverride.isLoading),error}}}return rt},[row,values,statusOverride]);const bundles=useMemo(()=>{const ThemeProvider=Wrapper?({children})=>jsx(Wrapper,{baseProps,children}):void 0;const bundle={id:"harness",label:"harness",components,contracts:{},...ThemeProvider?{ThemeProvider}:{}};return{scope:[bundle],forCell:()=>null}},[components,Wrapper,baseProps]);const environment=useMemo(()=>{const pageActions=Object.fromEntries(Object.keys(actions??{}).map(k=>[k,async input=>(console.info(`[harness] action ${k}`,input),{ok:true})]));window.__ENGINE_HARNESS_DIAGNOSTICS=[];return{core:{},navigate:()=>{},store:getStackStore(),actionsFor:cell=>cell.actions?projectCellActions(cell.actions,pageActions):Object.keys(pageActions).length?pageActions:void 0,onCellError:(cellId,error)=>console.error(`[harness] cell "${cellId}" failed:`,error),onDiagnostic:d=>{window.__ENGINE_HARNESS_DIAGNOSTICS.push({code:d.code,severity:d.severity,message:d.message,...d.cellId?{cellId:d.cellId}:{}});if(d.severity==="error")console.error(`[harness] ${d.code}: ${d.message}`)}}},[actions]);return jsx(PageRenderer,{runtime,bundles,params:{},baseProps,context:{environment:"harness"},environment})}function pageRow(id,json){return{id,name:json.name,org_id:null,project_id:null,process_id:null,graph_node_id:null,page_type:json.page_type??null,status:"published",is_template:json.is_template??false,content:json.content??{cells:[]},layout:json.layout??{type:"stack",gap:16},metadata:json.metadata??null}}function Index({fixtures,pages}){useEffect(()=>void(window.__ENGINE_HARNESS_READY=true),[]);const link=q=>`?${q}`;return jsxs("main",{style:{fontFamily:"system-ui, sans-serif",padding:24,maxWidth:960},children:[jsx("h1",{children:"Harness"}),jsx("h2",{children:"Fixtures"}),fixtures.map(([name,scenarios])=>jsxs("section",{children:[jsx("h3",{children:name}),jsx("ul",{children:scenarios.map(s=>jsxs("li",{children:[jsx("a",{href:link(`fixture=${encodeURIComponent(name)}&scenario=${encodeURIComponent(s.name)}`),children:s.name})," \xB7 ",jsx("a",{href:link(`fixture=${encodeURIComponent(name)}&scenario=${encodeURIComponent(s.name)}&container=320`),children:"in 320px"})]},s.name))})]},name)),jsx("h2",{children:"Pages"}),jsx("ul",{children:pages.map(p=>jsx("li",{children:jsx("a",{href:link(`page=${encodeURIComponent(p)}`),children:p})},p))})]})}function mountHarness(sources){const q=new URLSearchParams(window.location.search);const components=Object.assign({},...Object.values(sources.barrels));const fixtures=Object.entries(sources.fixtures).map(([path,mod])=>[fixtureName(path),[...mod.scenarios??[]]]).sort(([a],[b])=>a.localeCompare(b));const pages=Object.fromEntries(Object.entries(sources.pages).map(([path,json])=>[pageKey(path),{json,mock:sources.mocks[path.replace(/page\.json$/,"mock.json")]}]));let body;const fixture=q.get("fixture");const page=q.get("page");if(fixture){const scenario=fixtures.find(([n])=>n===fixture)?.[1].find(s=>s.name===q.get("scenario"));if(!scenario){window.__ENGINE_HARNESS_ERROR=`no scenario "${q.get("scenario")}" for ${fixture}`;body=null}else if(!isJson(scenario.props??{})){const Direct=components[fixture];if(!Direct)window.__ENGINE_HARNESS_ERROR=`${fixture} is not exported from any barrel`;const baseProps={...FIXTURE_BASE_PROPS,...scenario.baseProps};const element=Direct?jsx("div",{className:"cell","data-engine-direct":"",children:jsx(Direct,{...scenario.props,baseProps})}):null;body=sources.Wrapper?jsx(sources.Wrapper,{baseProps,children:element}):element}else{const cell={id:"fixture",component:fixture,props:scenario.props??{},...scenario.data?{data:{static:scenario.data}}:{},...scenario.selections?{selections:scenario.selections}:{},...scenario.viewState?{viewState:scenario.viewState}:{},...scenario.live?{live:scenario.live}:{}};body=jsx(RenderedPage,{row:pageRow(`${fixture}/${scenario.name}`,{name:`${fixture} \xB7 ${scenario.name}`,content:{cells:[cell]}}),values:{},actions:scenario.actions,baseProps:{...FIXTURE_BASE_PROPS,...scenario.baseProps},components,Wrapper:sources.Wrapper,statusOverride:scenario.status})}}else if(page){const entry=pages[page];if(!entry){window.__ENGINE_HARNESS_ERROR=`no page "${page}"`;body=null}else{const values={...entry.mock?.data};body=jsx(RenderedPage,{row:pageRow(page,entry.json),values,actions:entry.mock?.actions,baseProps:{...FIXTURE_BASE_PROPS,...entry.mock?.baseProps},components,Wrapper:sources.Wrapper})}}else{body=jsx(Index,{fixtures,pages:Object.keys(pages).sort()})}const container=Number(q.get("container"))||null;const framed=container?jsx("div",{"data-engine-container":"",style:{width:container,containerType:"inline-size",outline:"1px dashed #bbb"},children:body}):body;createRoot(document.getElementById("root")).render(jsx(Boundary,{children:jsx(Ready,{children:framed})}))}export{mountHarness};
|
package/src/index.d.mts
CHANGED
|
@@ -11,6 +11,8 @@ export type LineageSpec =
|
|
|
11
11
|
specifier?: string;
|
|
12
12
|
shared?: string[];
|
|
13
13
|
build?: { script: string; env?: Record<string, string> };
|
|
14
|
+
layer?: 'reset' | 'tokens' | 'renderer' | 'core' | 'charts' | 'org' | 'app' | 'theme';
|
|
15
|
+
cssPrefix?: string;
|
|
14
16
|
};
|
|
15
17
|
|
|
16
18
|
export type EngineConfig = {
|
|
@@ -41,6 +43,8 @@ export type Lineage = {
|
|
|
41
43
|
build?: { script: string; env?: Record<string, string> };
|
|
42
44
|
specifier?: string;
|
|
43
45
|
shared?: string[];
|
|
46
|
+
layer?: string;
|
|
47
|
+
cssPrefix?: string;
|
|
44
48
|
};
|
|
45
49
|
|
|
46
50
|
export const DEFAULT_CHECKS: string[];
|
package/src/lib/config.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{existsSync,readFileSync}from"node:fs";import{resolve}from"node:path";import{pathToFileURL}from"node:url";import{REPO_ROOT}from"./root.mjs";const MAIN_LINEAGE="main";const DEFAULT_CHECKS=["validate-externals","check-wired","check-routes","check-design-refs","check-skills","check-work-orders","check-cutover-ownership","check-fixtures","knowledge"];const PUBLIC_LINEAGE="public";const CONFIG_FILES=["engine.config.ts","engine.config.mts","engine.config.mjs","engine.config.js"];function defineConfig(config){return config}function lineageDefaults(name,kind){if(name===MAIN_LINEAGE){return{name,kind:"main",entry:"src/index.ts",sourceRoot:null,dist:"dist"}}if(name===PUBLIC_LINEAGE){return{name,kind:"public",entry:"src/index.public.ts",sourceRoot:"components/public/",dist:"dist-public"}}const k=kind??"page";return{name,kind:k,entry:`src/index.${name}.ts`,sourceRoot:k==="form"?`components/form/${name}/`:k==="shared"?`${name}/`:`components/project_page/${name}/`,dist:`dist-bundles/${name}`}}function normalize(raw,origin){if(!raw||typeof raw!=="object")throw new Error(`[engine] ${origin} must export a config object`);if(typeof raw.org!=="string"||!raw.org)throw new Error(`[engine] ${origin}: \`org\` (the org slug) is required`);const list=raw.lineages??[MAIN_LINEAGE];const lineages=list.map(l=>{const spec=typeof l==="string"?{name:l}:l;if(!spec?.name)throw new Error(`[engine] ${origin}: every lineage needs a name`);return{...lineageDefaults(spec.name,spec.kind),...spec}});const mainAt=lineages.findIndex(l=>l.name===MAIN_LINEAGE);if(mainAt>0)throw new Error(`[engine] ${origin}: main must be the first lineage`);if(mainAt===-1&&!lineages.every(l=>l.kind==="shared")){throw new Error(`[engine] ${origin}: lineages must start with "main", unless every lineage is shared`)}for(const l of lineages){if(l.kind==="shared"&&!/^@[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$/.test(l.specifier??"")){throw new Error(`[engine] ${origin}: shared lineage "${l.name}" needs a specifier like "@stack/${l.name}"`)}}const gated=raw.checks?.gated??{};const checks={run:raw.checks?.run??DEFAULT_CHECKS,peerRepos:raw.checks?.peerRepos??[],gated:{projectTemplates:gated.projectTemplates??[],orgTemplates:gated.orgTemplates??[]}};const shared=raw.shared??[];const harness={wrapper:raw.harness?.wrapper??null,widths:raw.harness?.widths??[390,768,1280],container:raw.harness?.container??320,overflow:raw.harness?.overflow??"warn",output:raw.harness?.output??"test/visual/__output__",alias:raw.harness?.alias??{}};return{org:raw.org,lineages,checks,shared,harness}}const normalizeForTest=raw=>normalize(raw,"test");let cached;async function loadConfig(){if(cached)return cached;const file=CONFIG_FILES.map(f=>resolve(REPO_ROOT,f)).find(f=>existsSync(f));if(file){const mod=await import(pathToFileURL(file).href);cached=normalize(mod.default??mod,file);return cached}const pkg=JSON.parse(readFileSync(resolve(REPO_ROOT,"package.json"),"utf8"));let org=pkg.oaBundle?.name;const orgJson=resolve(REPO_ROOT,"template/config/org.json");if(existsSync(orgJson))org=JSON.parse(readFileSync(orgJson,"utf8")).slug??org;const lineages=(pkg.oaBundle?.lineages??[MAIN_LINEAGE]).map(n=>n==="workbooks"?{name:n,kind:"form"}:n);cached=normalize({org,lineages},"package.json oaBundle");return cached}async function lineageConfig(name){const{lineages}=await loadConfig();return lineages.find(l=>l.name===name)??lineageDefaults(name)}export{DEFAULT_CHECKS,MAIN_LINEAGE,PUBLIC_LINEAGE,defineConfig,lineageConfig,lineageDefaults,loadConfig,normalizeForTest};
|
|
1
|
+
import{existsSync,readFileSync}from"node:fs";import{resolve}from"node:path";import{pathToFileURL}from"node:url";import{REPO_ROOT}from"./root.mjs";const MAIN_LINEAGE="main";const DEFAULT_CHECKS=["validate-externals","check-wired","check-routes","check-design-refs","check-skills","check-work-orders","check-cutover-ownership","check-fixtures","check-tokens","check-css-scope","knowledge"];const PUBLIC_LINEAGE="public";const CONFIG_FILES=["engine.config.ts","engine.config.mts","engine.config.mjs","engine.config.js"];function defineConfig(config){return config}function lineageDefaults(name,kind){if(name===MAIN_LINEAGE){return{name,kind:"main",entry:"src/index.ts",sourceRoot:null,dist:"dist"}}if(name===PUBLIC_LINEAGE){return{name,kind:"public",entry:"src/index.public.ts",sourceRoot:"components/public/",dist:"dist-public"}}const k=kind??"page";return{name,kind:k,entry:`src/index.${name}.ts`,sourceRoot:k==="form"?`components/form/${name}/`:k==="shared"?`${name}/`:`components/project_page/${name}/`,dist:`dist-bundles/${name}`}}function normalize(raw,origin){if(!raw||typeof raw!=="object")throw new Error(`[engine] ${origin} must export a config object`);if(typeof raw.org!=="string"||!raw.org)throw new Error(`[engine] ${origin}: \`org\` (the org slug) is required`);const list=raw.lineages??[MAIN_LINEAGE];const lineages=list.map(l=>{const spec=typeof l==="string"?{name:l}:l;if(!spec?.name)throw new Error(`[engine] ${origin}: every lineage needs a name`);return{...lineageDefaults(spec.name,spec.kind),...spec}});const mainAt=lineages.findIndex(l=>l.name===MAIN_LINEAGE);if(mainAt>0)throw new Error(`[engine] ${origin}: main must be the first lineage`);if(mainAt===-1&&!lineages.every(l=>l.kind==="shared")){throw new Error(`[engine] ${origin}: lineages must start with "main", unless every lineage is shared`)}for(const l of lineages){if(l.kind==="shared"&&!/^@[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$/.test(l.specifier??"")){throw new Error(`[engine] ${origin}: shared lineage "${l.name}" needs a specifier like "@stack/${l.name}"`)}}const gated=raw.checks?.gated??{};const checks={run:raw.checks?.run??DEFAULT_CHECKS,peerRepos:raw.checks?.peerRepos??[],gated:{projectTemplates:gated.projectTemplates??[],orgTemplates:gated.orgTemplates??[]}};const shared=raw.shared??[];const harness={wrapper:raw.harness?.wrapper??null,widths:raw.harness?.widths??[390,768,1280],container:raw.harness?.container??320,overflow:raw.harness?.overflow??"warn",output:raw.harness?.output??"test/visual/__output__",alias:raw.harness?.alias??{}};return{org:raw.org,lineages,checks,shared,harness}}const normalizeForTest=raw=>normalize(raw,"test");let cached;async function loadConfig(){if(cached)return cached;const file=CONFIG_FILES.map(f=>resolve(REPO_ROOT,f)).find(f=>existsSync(f));if(file){const mod=await import(pathToFileURL(file).href);cached=normalize(mod.default??mod,file);return cached}const pkg=JSON.parse(readFileSync(resolve(REPO_ROOT,"package.json"),"utf8"));let org=pkg.oaBundle?.name;const orgJson=resolve(REPO_ROOT,"template/config/org.json");if(existsSync(orgJson))org=JSON.parse(readFileSync(orgJson,"utf8")).slug??org;const lineages=(pkg.oaBundle?.lineages??[MAIN_LINEAGE]).map(n=>n==="workbooks"?{name:n,kind:"form"}:n);cached=normalize({org,lineages},"package.json oaBundle");return cached}async function lineageConfig(name){const{lineages}=await loadConfig();return lineages.find(l=>l.name===name)??lineageDefaults(name)}export{DEFAULT_CHECKS,MAIN_LINEAGE,PUBLIC_LINEAGE,defineConfig,lineageConfig,lineageDefaults,loadConfig,normalizeForTest};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const LAYER_ORDER=["reset","tokens","renderer","core","charts","org","app","theme"];function layerFor(lineage){if(lineage.layer){if(!LAYER_ORDER.includes(lineage.layer))throw new Error(`[layers] lineage "${lineage.name}": layer "${lineage.layer}" is not one of ${LAYER_ORDER.join(", ")}`);return lineage.layer}if(lineage.kind==="shared")return LAYER_ORDER.includes(lineage.name)?lineage.name:"core";if(lineage.kind==="main")return"org";return"app"}function layerCss(postcss,css,layer){const root=postcss.parse(css);const head=[];const kept=[];const wrapped=[];root.each(node=>{if(node.type==="atrule"&&(node.name==="charset"||node.name==="import"))head.push(node);else if(node.type==="atrule"&&node.name==="layer"&&LAYER_ORDER.includes(node.params.trim())&&node.nodes)kept.push(node);else if(node.type==="comment")return;else wrapped.push(node)});const out=postcss.root();for(const n of head)out.append(n.clone());for(const n of kept)out.append(n.clone());if(wrapped.length){const rule=postcss.atRule({name:"layer",params:layer});for(const n of wrapped)rule.append(n.clone());out.append(rule)}return out.toString()}export{LAYER_ORDER,layerCss,layerFor};
|
package/src/lib/run.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{spawnSync}from"node:child_process";import{existsSync}from"node:fs";import{dirname,resolve}from"node:path";import{fileURLToPath}from"node:url";import{REPO_ROOT}from"./root.mjs";const COMMANDS_DIR=resolve(dirname(fileURLToPath(import.meta.url)),"..","commands");const TSX=import.meta.resolve("tsx/esm");const COMMANDS={build:"build.mjs",deploy:"deploy.mjs",check:"check.mjs",harness:"harness.mjs","test-visual":"test-visual.mjs",template:"template.mjs",upload:"upload-bundle.mjs",register:"register-components.mjs",cutover:"cutover.mjs",knowledge:"emit-knowledge.mjs",contracts:"emit-contracts.mjs","bundle-size":"bundle-size.mjs","check-bundle-leak":"check-bundle-leak.mjs","validate-externals":"validate-externals.mjs","check-wired":"check-wired-bindings.mjs","check-routes":"check-template-routes.mjs","check-design-refs":"check-design-refs.mjs","check-skills":"check-skills.mjs","check-work-orders":"check-work-orders.mjs","check-cutover-ownership":"check-cutover-ownership.mjs","check-fixtures":"check-fixtures.mjs","check-props-schema":"check-props-schema.mjs"};function commandFile(name){if(!COMMANDS[name])return null;const file=resolve(COMMANDS_DIR,COMMANDS[name]);const ts=file.replace(/\.mjs$/,".mts");return existsSync(file)?file:existsSync(ts)?ts:null}function runCommand(name,args=[],env={}){const file=commandFile(name);if(!file)throw new Error(`[engine] unknown command "${name}"`);const r=spawnSync(process.execPath,["--import",TSX,file,...args],{cwd:REPO_ROOT,stdio:"inherit",env:{...process.env,ENGINE_ROOT:REPO_ROOT,...env}});return r.status??1}export{COMMANDS,commandFile,runCommand};
|
|
1
|
+
import{spawnSync}from"node:child_process";import{existsSync}from"node:fs";import{dirname,resolve}from"node:path";import{fileURLToPath}from"node:url";import{REPO_ROOT}from"./root.mjs";const COMMANDS_DIR=resolve(dirname(fileURLToPath(import.meta.url)),"..","commands");const TSX=import.meta.resolve("tsx/esm");const COMMANDS={build:"build.mjs",deploy:"deploy.mjs",check:"check.mjs",harness:"harness.mjs","test-visual":"test-visual.mjs",template:"template.mjs",upload:"upload-bundle.mjs",register:"register-components.mjs",cutover:"cutover.mjs",knowledge:"emit-knowledge.mjs",contracts:"emit-contracts.mjs","bundle-size":"bundle-size.mjs","check-bundle-leak":"check-bundle-leak.mjs","validate-externals":"validate-externals.mjs","check-wired":"check-wired-bindings.mjs","check-routes":"check-template-routes.mjs","check-design-refs":"check-design-refs.mjs","check-skills":"check-skills.mjs","check-work-orders":"check-work-orders.mjs","check-cutover-ownership":"check-cutover-ownership.mjs","check-fixtures":"check-fixtures.mjs","check-props-schema":"check-props-schema.mjs","check-tokens":"check-tokens.mjs","check-css-scope":"check-css-scope.mjs"};function commandFile(name){if(!COMMANDS[name])return null;const file=resolve(COMMANDS_DIR,COMMANDS[name]);const ts=file.replace(/\.mjs$/,".mts");return existsSync(file)?file:existsSync(ts)?ts:null}function runCommand(name,args=[],env={}){const file=commandFile(name);if(!file)throw new Error(`[engine] unknown command "${name}"`);const r=spawnSync(process.execPath,["--import",TSX,file,...args],{cwd:REPO_ROOT,stdio:"inherit",env:{...process.env,ENGINE_ROOT:REPO_ROOT,...env}});return r.status??1}export{COMMANDS,commandFile,runCommand};
|