@teispace/next-maker 5.0.3 → 5.0.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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [5.0.5](https://github.com/teispace/npm-packages/compare/next-maker-v5.0.4...next-maker-v5.0.5) (2026-09-06)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **next-maker:** let locale and component run without a terminal ([#170](https://github.com/teispace/npm-packages/issues/170)) ([fa818d9](https://github.com/teispace/npm-packages/commit/fa818d94868e726d389a6cb27ea90fc414a09198))
9
+
10
+ ## [5.0.4](https://github.com/teispace/npm-packages/compare/next-maker-v5.0.3...next-maker-v5.0.4) (2026-09-06)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **next-maker:** keep generated placeholders free of empty object types ([#168](https://github.com/teispace/npm-packages/issues/168)) ([b0b3d40](https://github.com/teispace/npm-packages/commit/b0b3d40f6d9d8e3ea8966143527be58f8bbdf2e1))
16
+
3
17
  ## [5.0.3](https://github.com/teispace/npm-packages/compare/next-maker-v5.0.2...next-maker-v5.0.3) (2026-09-06)
4
18
 
5
19
 
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{Command as Fp}from"commander";var Ae={name:"@teispace/next-maker",version:"5.0.3",description:"Create and grow Next.js 16 applications from the Teispace starter: composable init, feature-aware setup and doctor, and generators for the server-first data layer.",keywords:["nextjs","react","typescript","tailwindcss","starter","template","redux","zustand","tanstack-query","server-actions","cli"],type:"module",homepage:"https://github.com/teispace/npm-packages/tree/main/packages/next-maker#readme",bugs:{url:"https://github.com/teispace/npm-packages/issues"},license:"MIT",author:"Teispace",files:["dist","README.md","LICENSE","CHANGELOG.md"],bin:"dist/index.js",repository:{type:"git",url:"git+https://github.com/teispace/npm-packages.git",directory:"packages/next-maker"},scripts:{build:"tsx build.ts",start:"node dist/index.js",dev:"tsx --watch src/index.ts",test:"vitest run","test:watch":"vitest","test:cov":"vitest run --coverage","type-check":"tsc --noEmit",clean:"rm -rf dist",prepublishOnly:"yarn clean && yarn build",smoke:"tsx scripts/smoke.ts"},dependencies:{commander:"^15.0.0",degit:"^3.8.0",enquirer:"^2.4.1",ora:"^9.4.1",picocolors:"^1.1.1","png-to-ico":"^3.0.2",sharp:"^0.35.3"},devDependencies:{"@types/degit":"^2.8.6","@types/node":"^26.2.0",esbuild:"^0.28.2",tsx:"^4.23.12",typescript:"^6.0.3",vitest:"^4.1.11"},engines:{node:">=24.0.0"},publishConfig:{access:"public",registry:"https://registry.npmjs.org/"}};import{copyFile as ea}from"node:fs/promises";import At from"node:path";import I from"picocolors";var sn=/@next-maker:([\w-]+)(?::(start|end))?/,Ys=/^\s*(?:\{\s*\/\*.*?\*\/\s*\}|\/\*.*?\*\/|\/\/.*|#.*)\s*$/,Qs=e=>e.replace(/\s*\{\s*\/\*[^*]*@next-maker:[^*]*\*\/\s*\}\s*$/,"").replace(/\s*\/\*[^*]*@next-maker:[^*]*\*\/\s*$/,"").replace(/\s*\/\/[^\n]*@next-maker:[^\n]*$/,"").replace(/\s*#[^\n]*@next-maker:[^\n]*$/,""),Xt=(e,{off:t})=>{let r=e.split(`
2
+ import{Command as Fp}from"commander";var Ae={name:"@teispace/next-maker",version:"5.0.5",description:"Create and grow Next.js 16 applications from the Teispace starter: composable init, feature-aware setup and doctor, and generators for the server-first data layer.",keywords:["nextjs","react","typescript","tailwindcss","starter","template","redux","zustand","tanstack-query","server-actions","cli"],type:"module",homepage:"https://github.com/teispace/npm-packages/tree/main/packages/next-maker#readme",bugs:{url:"https://github.com/teispace/npm-packages/issues"},license:"MIT",author:"Teispace",files:["dist","README.md","LICENSE","CHANGELOG.md"],bin:"dist/index.js",repository:{type:"git",url:"git+https://github.com/teispace/npm-packages.git",directory:"packages/next-maker"},scripts:{build:"tsx build.ts",start:"node dist/index.js",dev:"tsx --watch src/index.ts",test:"vitest run","test:watch":"vitest","test:cov":"vitest run --coverage","type-check":"tsc --noEmit",clean:"rm -rf dist",prepublishOnly:"yarn clean && yarn build",smoke:"tsx scripts/smoke.ts"},dependencies:{commander:"^15.0.0",degit:"^3.8.0",enquirer:"^2.4.1",ora:"^9.4.1",picocolors:"^1.1.1","png-to-ico":"^3.0.2",sharp:"^0.35.3"},devDependencies:{"@types/degit":"^2.8.6","@types/node":"^26.2.0",esbuild:"^0.28.2",tsx:"^4.23.12",typescript:"^6.0.3",vitest:"^4.1.11"},engines:{node:">=24.0.0"},publishConfig:{access:"public",registry:"https://registry.npmjs.org/"}};import{copyFile as ea}from"node:fs/promises";import At from"node:path";import I from"picocolors";var sn=/@next-maker:([\w-]+)(?::(start|end))?/,Ys=/^\s*(?:\{\s*\/\*.*?\*\/\s*\}|\/\*.*?\*\/|\/\/.*|#.*)\s*$/,Qs=e=>e.replace(/\s*\{\s*\/\*[^*]*@next-maker:[^*]*\*\/\s*\}\s*$/,"").replace(/\s*\/\*[^*]*@next-maker:[^*]*\*\/\s*$/,"").replace(/\s*\/\/[^\n]*@next-maker:[^\n]*$/,"").replace(/\s*#[^\n]*@next-maker:[^\n]*$/,""),Xt=(e,{off:t})=>{let r=e.split(`
3
3
  `),n=[];for(let o=0;o<r.length;o++){let s=r[o],i=s.match(sn);if(!i){n.push(s);continue}let[,a,c]=i,l=t.has(a);if(c==="start"){let u=Zs(r,o+1,a);l&&(o=u);continue}if(c==="end")continue;let p=Ys.test(s);if(l){p&&o++;continue}p||n.push(Qs(s))}return n.join(`
4
4
  `)},Zs=(e,t,r)=>{for(let n=t;n<e.length;n++){let o=e[n].match(sn);if(o&&o[1]===r&&o[2]==="end")return n}throw new Error(`Anchor @next-maker:${r}:start has no matching :end`)},ze=e=>e.includes("@next-maker:"),an=(e,t)=>{let r=e.split(`
5
5
  `),n=[],o=new RegExp(`^import\\s+${t}\\s+from\\s+['"][^'"]+['"];?\\s*$`),s=/^(import\s+(?:type\s+)?)\{([^}]+)\}(\s+from\s+['"][^'"]+['"];?\s*)$/;for(let i of r){if(o.test(i))continue;let a=i.match(s);if(a){let c=a[2].split(",").map(p=>p.trim()).filter(Boolean),l=c.filter(p=>p.replace(/^type\s+/,"").split(/\s+as\s+/)[0]!==t);if(l.length===0)continue;if(l.length<c.length){n.push(`${a[1]}{ ${l.join(", ")} }${a[3]}`);continue}}n.push(i)}return n.join(`
@@ -263,7 +263,8 @@ export interface ${t}State {
263
263
  error: string | null;
264
264
  }
265
265
  `:`export interface ${t}Props {
266
- // Props for the ${t} component
266
+ /** Extra classes for the root element. Add this feature's own props here. */
267
+ className?: string;
267
268
  }
268
269
  `};var so=e=>{let{componentName:t,camelName:r,typesImportPath:n}=e;return`import type { StateCreator } from 'zustand';
269
270
 
@@ -574,7 +575,8 @@ export default function ${e.componentName}Error({
574
575
  import { createContext, useContext, useMemo } from 'react';
575
576
 
576
577
  type ${n} = {
577
- // TODO: declare context value fields
578
+ /** Replace with this provider's own fields. */
579
+ ready: boolean;
578
580
  };
579
581
 
580
582
  const ${o} = createContext<${n} | null>(null);
@@ -588,7 +590,7 @@ export const ${s} = (): ${n} => {
588
590
  };
589
591
 
590
592
  export const ${t} = ({ children }: { children: React.ReactNode }) => {
591
- const value = useMemo<${n}>(() => ({}), []);
593
+ const value = useMemo<${n}>(() => ({ ready: true }), []);
592
594
  return <${o}.Provider value={value}>{children}</${o}.Provider>;
593
595
  };
594
596
  `},xo=e=>yo(e,"Provider");var Ba=/^[A-Za-z][A-Za-z0-9-]*$/,Va=e=>e.includes("-")?$(e):e.charAt(0).toUpperCase()+e.slice(1),Tr=async e=>{let{name:t,projectPath:r}=e;if(!Ba.test(t))throw new Error(`Invalid provider name "${t}". Use kebab-case or PascalCase letters and digits only.`);let n=Va(t).replace(/Provider$/,""),o=xo(n),s=o,i=Er.join(r,C.PROVIDERS),a=Er.join(i,`${s}.tsx`);if(w(a))throw new Error(`Provider already exists at ${Er.relative(r,a)}.`);return await Ga(i,{recursive:!0}),await P(a,wo({baseName:n})),{componentName:o,fileBaseName:s,providerFile:a}};import pt from"node:path";var oe=async e=>{let{projectPath:t,sourceFile:r,kind:n,symbolName:o}=e,s=pt.dirname(r),i=pt.basename(r).replace(/\.(tsx?|jsx?)$/i,""),a=n==="component"?".tsx":".ts",c=pt.join(s,`${i}.test${a}`),l=`./${i}`,p=Ha(s,pt.join(t,"test","test-utils")),u;return n==="component"?u=Mt({componentName:o,sourceImportPath:l,testUtilsImportPath:p,hasState:!!e.hasState,hasI18n:!!e.hasI18n}):n==="hook"?u=co({hookName:o,sourceImportPath:l,withStore:!!e.hookUsesStore,testUtilsImportPath:e.hookUsesStore?p:void 0}):u=po({camelName:o,sourceImportPath:l}),await P(c,u),c},Ha=(e,t)=>{let r=pt.relative(e,t).replace(/\\/g,"/");return r.startsWith(".")?r:`./${r}`};import{readFile as qa,writeFile as Ja}from"node:fs/promises";import za from"node:path";var Ge=(e,t)=>{let r=/import\s+.*\s+from\s+['"].*['"];?\n/g,n=e.match(r);if(n&&n.length>0){let o=n[n.length-1],s=e.lastIndexOf(o);return e.slice(0,s+o.length)+t+`
@@ -616,7 +618,7 @@ ${o}</${t}>`;return e.replace(r,i)},Ro=(e,t)=>{let r=`export * from './${t}';`;i
616
618
  `),o=[],s=[];for(let u of n)/^export \* from '\.\/.*';\s*$/.test(u)?o.push(u):s.push(u);let i=[...o,r].sort(),a=n.findIndex(u=>/^export \* from '\.\//.test(u));if(a===-1)return`${r}
617
619
  ${e.replace(/^\n+/,"")}`;let c=n.slice(0,a),l=n.findIndex((u,f)=>f>a&&!/^export \* from '\.\//.test(u)),p=l===-1?[]:n.slice(l);return[...c,...i,...p].join(`
618
620
  `)},oc=C.PROVIDERS,sc=C.ROOT_PROVIDER,ic=C.PROVIDERS_INDEX,Co=async(e,t={fileExists:w,readFile:R})=>{let r=Lt.join(e,sc);if(t.fileExists(r))return r;let n=Lt.join(e,oc);if(!t.fileExists(n))return null;let{readdir:o}=await import("node:fs/promises"),i=(await o(n).catch(()=>[])).filter(c=>c.endsWith(".tsx")),a=null;for(let c of i){let l=Lt.join(n,c),p=await t.readFile(l);if(!/\{children\}/.test(p))continue;let f=((p.split("{children}")[0]??"").match(/<[A-Z][A-Za-z0-9_]*\b/g)??[]).length;(!a||f>a.depth)&&(a={file:l,depth:f})}return a?.file??null},Fr=async e=>{let{projectPath:t,componentName:r,fileBaseName:n}=e,o=await Co(t);if(o){let a=await R(o),c=a;(!/from '\.\//.test(a)||!a.includes(`{ ${r} }`))&&(c=Ge(c,`import { ${r} } from './${n}';`)),c=jo(c,r),c!==a&&await P(o,c)}let s=Lt.join(t,ic),i=null;if(w(s)){let a=await R(s),c=Ro(a,n);c!==a&&await P(s,c),i=s}return{rootProviderFile:o,barrelFile:i}};import{readFile as Oo,writeFile as Ao}from"node:fs/promises";import Io from"node:path";var mt=async e=>{let{projectPath:t,name:r,persist:n,importPath:o}=e,s=Io.join(t,"src","store","rootReducer.ts"),i=Io.join(t,"src","store","index.ts"),a=G(r),c=o.replace(/^src\//,"@/");try{let l=await Oo(s,"utf-8");if(l=Ge(l,`import { ${a}Slice } from '${c}';`),l=jr(l,`${a}Slice`),await Ao(s,l),n&&w(i)){let p=await Oo(i,"utf-8");p=Ge(p,`import { ${a}Persistence } from '${c}';`),p=Rr(p,`${a}Persistence`),await Ao(i,p)}}catch(l){throw new Error(`Failed to register slice '${r}': ${l}`,{cause:l})}};import{readFile as ac,writeFile as cc}from"node:fs/promises";import pc from"node:path";var Te=async(e,t)=>{let r=pc.join(e,"src","i18n","translations","en.json");if(!w(r))return;let n=await ac(r,"utf-8"),o=JSON.parse(n);o[t]||(o[t]={title:t,description:`${t} page description`},await cc(r,`${JSON.stringify(o,null,2)}
619
- `))};import lc from"enquirer";var{prompt:mc}=lc,No=async(e,t={})=>{let r=[];e||r.push({type:"input",name:"componentName",message:"Component name (kebab-case):",validate:o=>o?/^[a-z][a-z0-9-]*$/.test(o)?!0:"Use lowercase letters, numbers, and hyphens only":"Component name is required"}),t.client===void 0&&r.push({type:"confirm",name:"isClient",message:"Add 'use client' directive?",initial:!1});let n=r.length>0?await mc(r):{};return{componentName:e??n.componentName,isClient:t.client??n.isClient??!1}};var Fo=e=>{e.command("component [name]").description("Generate a shared component").option("--client","Add 'use client' directive").option("--i18n","Add useTranslations hook").option("--feature <path>","Generate in feature directory (e.g., src/features/auth)").option("--test","Also generate a sibling test file").option("--no-test","Skip test file generation").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();m(X.cyan(`
621
+ `))};import lc from"enquirer";var{prompt:mc}=lc,No=async(e,t={})=>{let r=[];e||r.push({type:"input",name:"componentName",message:"Component name (kebab-case):",validate:o=>o?/^[a-z][a-z0-9-]*$/.test(o)?!0:"Use lowercase letters, numbers, and hyphens only":"Component name is required"}),t.client===void 0&&r.push({type:"confirm",name:"isClient",message:"Add 'use client' directive?",initial:!1});let n=r.length>0?await mc(r):{};return{componentName:e??n.componentName,isClient:t.client??n.isClient??!1}};var Fo=e=>{e.command("component [name]").description("Generate a shared component").option("--client","Add 'use client' directive").option("--no-client","Keep the component a Server Component").option("--i18n","Add useTranslations hook").option("--feature <path>","Generate in feature directory (e.g., src/features/auth)").option("--test","Also generate a sibling test file").option("--no-test","Skip test file generation").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();m(X.cyan(`
620
622
  \u{1F9E9} Component Generator
621
623
  `)),h.start("Detecting project setup...");let s=await O(n);h.succeed("Project setup detected");let i=await No(t,{client:r.client});M(i.componentName,"component name"),r.feature&&W(r.feature,"feature path");let a=$(i.componentName),c=i.isClient,l=r.i18n??!1,p=uc(r,s.hasTests);h.start("Generating component..."),await fr({name:i.componentName,projectPath:n,isClient:c||l,hasI18n:l,featurePath:r.feature}),h.succeed("Component generated"),l&&await Te(n,a);let u=null;if(p){let d=r.feature?Mr.join(n,r.feature,"components",`${a}.tsx`):Mr.join(n,"src/components/common",a,`${a}.tsx`);h.start("Generating test..."),u=await oe({projectPath:n,sourceFile:d,kind:"component",symbolName:a,hasState:s.state!=="none",hasI18n:s.hasI18n}),h.succeed("Test generated")}let f=r.feature?`${r.feature}/components/${a}.tsx`:`src/components/common/${a}/${a}.tsx`;await k(n,o),m(X.green(`
622
624
  \u2728 Component '${a}' created successfully!
@@ -653,7 +655,7 @@ ${e.map(r=>` { src: '${r.src}', sizes: '${r.sizes}', type: '${r.type}'${r.pur
653
655
  `)),h.start("Detecting project setup...");let s=await O(n);h.succeed("Project setup detected");let i=s.hasI18n&&r.locale!==!1;m(Vt.dim(` i18n: ${i?"\u2713":"\u2717"}
654
656
  `)),h.start("Generating layout...");let a=await vr({segment:t,at:r.at,projectPath:n,hasI18n:i,withGroup:!!r.group});h.succeed("Layout generated"),await k(n,o),m(Vt.green(`
655
657
  \u2728 ${a.componentName} created!
656
- `)),m(Vt.dim(` \u{1F4C4} ${a.displayPath}`)),m("")}catch(n){h.fail("Layout generation failed"),b(`${n instanceof Error?n.message:n}`),process.exit(1)}})};import Q from"picocolors";import zc from"enquirer";var{prompt:Wc}=zc,cs=async(e,t={})=>{let r=[];e||r.push({type:"input",name:"code",message:"Locale code (e.g., es, fr, de):",validate:o=>o?/^[a-z]{2}(-[A-Z]{2})?$/.test(o)?!0:"Use format: xx or xx-XX (e.g., es, pt-BR)":"Locale code is required"}),t.name||r.push({type:"input",name:"name",message:"Language name (e.g., Spanish, French):",validate:o=>o?!0:"Language name is required"}),t.country||r.push({type:"input",name:"country",message:"Country (e.g., Spain, France):",validate:o=>o?!0:"Country is required"}),t.flag||r.push({type:"input",name:"flag",message:"Flag emoji (e.g., \u{1F1EA}\u{1F1F8}, \u{1F1EB}\u{1F1F7}):",validate:o=>o?!0:"Flag emoji is required"}),t.copyTranslations===void 0&&r.push({type:"confirm",name:"copyTranslations",message:"Copy translations from English? (No = empty values)",initial:!1});let n=r.length>0?await Wc(r):{};return{code:e??n.code,name:t.name??n.name,country:t.country??n.country,flag:t.flag??n.flag,copyTranslations:t.copyTranslations??n.copyTranslations??!1}};var ps=e=>{e.command("locale [code]").description("Add a new locale/language").option("--copy-translations","Copy translations from English instead of empty values").option("--name <name>","Language name, e.g. Spanish").option("--country <country>","Country, e.g. Spain").option("--flag <emoji>","Flag emoji, e.g. \u{1F1EA}\u{1F1F8}").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();m(Q.cyan(`
658
+ `)),m(Vt.dim(` \u{1F4C4} ${a.displayPath}`)),m("")}catch(n){h.fail("Layout generation failed"),b(`${n instanceof Error?n.message:n}`),process.exit(1)}})};import Q from"picocolors";import zc from"enquirer";var{prompt:Wc}=zc,cs=async(e,t={})=>{let r=[];e||r.push({type:"input",name:"code",message:"Locale code (e.g., es, fr, de):",validate:o=>o?/^[a-z]{2}(-[A-Z]{2})?$/.test(o)?!0:"Use format: xx or xx-XX (e.g., es, pt-BR)":"Locale code is required"}),t.name||r.push({type:"input",name:"name",message:"Language name (e.g., Spanish, French):",validate:o=>o?!0:"Language name is required"}),t.country||r.push({type:"input",name:"country",message:"Country (e.g., Spain, France):",validate:o=>o?!0:"Country is required"}),t.flag||r.push({type:"input",name:"flag",message:"Flag emoji (e.g., \u{1F1EA}\u{1F1F8}, \u{1F1EB}\u{1F1F7}):",validate:o=>o?!0:"Flag emoji is required"}),t.copyTranslations===void 0&&r.push({type:"confirm",name:"copyTranslations",message:"Copy translations from English? (No = empty values)",initial:!1});let n=r.length>0?await Wc(r):{};return{code:e??n.code,name:t.name??n.name,country:t.country??n.country,flag:t.flag??n.flag,copyTranslations:t.copyTranslations??n.copyTranslations??!1}};var ps=e=>{e.command("locale [code]").description("Add a new locale/language").option("--copy-translations","Copy translations from English instead of empty values").option("--no-copy-translations","Start the new locale with empty values").option("--name <name>","Language name, e.g. Spanish").option("--country <country>","Country, e.g. Spain").option("--flag <emoji>","Flag emoji, e.g. \u{1F1EA}\u{1F1F8}").action(async(t,r)=>{try{let n=process.cwd(),o=Date.now();m(Q.cyan(`
657
659
  \u{1F30D} Locale Generator
658
660
  `)),h.start("Detecting project setup...");let s=await O(n);h.succeed("Project setup detected"),s.hasI18n||(h.fail("i18n is not set up in this project"),b("Please set up internationalization first"),m(Q.dim(`
659
661
  Run: npx @teispace/next-maker setup --i18n
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teispace/next-maker",
3
- "version": "5.0.3",
3
+ "version": "5.0.5",
4
4
  "description": "Create and grow Next.js 16 applications from the Teispace starter: composable init, feature-aware setup and doctor, and generators for the server-first data layer.",
5
5
  "keywords": [
6
6
  "nextjs",