@peripheries/engine 0.8.1 → 0.8.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peripheries/engine",
3
- "version": "0.8.1",
3
+ "version": "0.8.2",
4
4
  "description": "Build, check, knowledge and deploy for peripheries component repos",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{existsSync,readFileSync,readdirSync}from"node:fs";import{dirname,join,relative,resolve}from"node:path";import{fileURLToPath}from"node:url";import{REPO_ROOT as REPO_ROOT_}from"../lib/root.mjs";const repoRoot=REPO_ROOT_;const REQUIRE_BUILD=process.argv.includes("--require-build");const SENTINELS=[{needle:"VENDORED FROM THE HOST",what:"the host code kept in src/harness/host-compat"},{needle:"data-missing-component",what:"@peripheries/renderer (the page renderer)"},{needle:"[harness]",what:"harness render code"},{needle:"onUnresolvedReference",what:"the harness page renderer"}];function bundles(){const out=[];const main=resolve(repoRoot,"dist/index.js");if(existsSync(main))out.push(main);const bundleRoot=resolve(repoRoot,"dist-bundles");if(existsSync(bundleRoot)){for(const slug of readdirSync(bundleRoot)){const file=join(bundleRoot,slug,"index.js");if(existsSync(file))out.push(file)}}return out}const files=bundles();if(files.length===0){const msg="[check-bundle-leak] no built bundle found (dist/index.js, dist-bundles/*/index.js).";if(REQUIRE_BUILD){console.error(`${msg} Run \`npm run build\` first.`);process.exit(1)}console.warn(`${msg} Skipping (pass --require-build to make this fatal).`);process.exit(0)}let failed=false;for(const file of files){const source=readFileSync(file,"utf8");const hits=SENTINELS.filter(s=>source.includes(s.needle));const rel=relative(repoRoot,file);if(hits.length===0){console.log(`[check-bundle-leak] OK \u2014 ${rel} (${(source.length/1024).toFixed(0)} KB)`);continue}failed=true;console.error(`[check-bundle-leak] LEAK in ${rel}:`);for(const hit of hits){console.error(` \xB7 found "${hit.needle}" \u2014 ${hit.what} is in the shipped bundle`)}}if(failed){console.error('\n Something under src/components/ or a src/index*.ts barrel reached into\n src/harness/ or test/. Find it with:\n npx eslint "src/**/*.{ts,tsx}" (the no-restricted-imports guard)\n and move whatever is shared into src/components/_shared/ instead.');process.exit(1)}
2
+ import{existsSync,readFileSync,readdirSync}from"node:fs";import{join,relative,resolve}from"node:path";import{fileURLToPath}from"node:url";import{loadConfig}from"../lib/config.mjs";import{REPO_ROOT as REPO_ROOT_}from"../lib/root.mjs";import{loadSharedLineages}from"../lib/shared-lineages.mjs";const repoRoot=REPO_ROOT_;const REQUIRE_BUILD=process.argv.includes("--require-build");const SENTINELS=[{needle:"VENDORED FROM THE HOST",what:"the host code kept in src/harness/host-compat"},{needle:"data-missing-component",what:"@peripheries/renderer (the page renderer)"},{needle:"[harness]",what:"harness render code"},{needle:"onUnresolvedReference",what:"the harness page renderer"}];function stylesheetClasses(css){return[...new Set([...css.matchAll(/\.(-?[a-z][a-z0-9]*-[a-z0-9_-]+)/g)].map(m=>m[1]))]}function namedClasses(source,classes){return classes.filter(c=>new RegExp(`(^|[^a-z0-9_-])${c.replace(/[-]/g,"\\-")}([^a-z0-9_-]|$)`).test(source))}const COPY_THRESHOLD=5;async function lineageBundles(){try{const{lineages}=await loadConfig();const files=lineages.map(l=>resolve(repoRoot,l.dist,"index.js")).filter(f=>existsSync(f));return files.length?files:bundles()}catch{return bundles()}}async function sharedClasses(){try{const shared=await loadSharedLineages(await loadConfig());return shared.lineages.filter(l=>l.css&&existsSync(l.css)).map(l=>({specifier:l.specifier,classes:stylesheetClasses(readFileSync(l.css,"utf8"))})).filter(l=>l.classes.length>=COPY_THRESHOLD)}catch{return[]}}function bundles(){const out=[];const main2=resolve(repoRoot,"dist/index.js");if(existsSync(main2))out.push(main2);const bundleRoot=resolve(repoRoot,"dist-bundles");if(existsSync(bundleRoot)){for(const slug of readdirSync(bundleRoot)){const file=join(bundleRoot,slug,"index.js");if(existsSync(file))out.push(file)}}return out}async function main(){const files=[...new Set(await lineageBundles())];const shared=await sharedClasses();if(files.length===0){const msg="[check-bundle-leak] no built bundle found (each lineage's index.js).";if(REQUIRE_BUILD){console.error(`${msg} Run \`npm run build\` first.`);return 1}console.warn(`${msg} Skipping (pass --require-build to make this fatal).`);return 0}let failed=false;for(const file of files){const source=readFileSync(file,"utf8");const hits=SENTINELS.filter(s=>source.includes(s.needle));for(const{specifier,classes}of shared){const named=namedClasses(source,classes);if(named.length>=COPY_THRESHOLD)hits.push({needle:named.slice(0,3).join('", "'),what:`a copy of ${specifier} (${named.length} of its classes; keep it in the lineage's \`shared\`)`})}const rel=relative(repoRoot,file);if(hits.length===0){console.log(`[check-bundle-leak] OK \u2014 ${rel} (${(source.length/1024).toFixed(0)} KB)`);continue}failed=true;console.error(`[check-bundle-leak] LEAK in ${rel}:`);for(const hit of hits){console.error(` \xB7 found "${hit.needle}" \u2014 ${hit.what} is in the shipped bundle`)}}if(shared.length)console.log(`[check-bundle-leak] checked for copies of ${shared.map(l=>l.specifier).join(", ")}`);if(failed){console.error('\n Something under src/components/ or a src/index*.ts barrel reached into\n src/harness/ or test/. Find it with:\n npx eslint "src/**/*.{ts,tsx}" (the no-restricted-imports guard)\n and move whatever is shared into src/components/_shared/ instead. A copy\n of a shared lineage means a lineage imports it without listing it in its\n `shared` (engine.config.ts), so the build bundled it instead of leaving it external.');return 1}return 0}if(process.argv[1]&&resolve(process.argv[1])===fileURLToPath(import.meta.url)){process.exit(await main())}export{COPY_THRESHOLD,namedClasses,stylesheetClasses};
@@ -1 +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};
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"||lineage.kind==="public")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};