@knapsack/renderer-react 4.70.0--canary.3797.b249674.0 → 4.70.0--canary.4821.e250df4.0

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.mjs CHANGED
@@ -1,46 +1,1305 @@
1
- import Ie from 'sleep-promise';
2
- import { RendererWebpackBase } from '@knapsack/renderer-webpack-base';
3
- import { makeShortId, pascalCase, isFirstLetterCapital, removeWrappingDoubleQuotes } from '@knapsack/utils';
4
- import { log, knapsackEvents } from '@knapsack/app';
5
- import { babelCodeForBrowser, createSlotOptionsHtmlTags } from '@knapsack/app/renderers';
6
- import { rendererIds, isNumberProp, isOptionsProp } from '@knapsack/types';
7
- import { findUpPkgJson, formatCode, getJsExportNames, exists, readFile, findUp, resolvePath, getModulePkgJson, copy } from '@knapsack/file-utils';
8
- import h, { join, parse, relative } from 'path';
9
- import { createCreator, tasks } from '@knapsack/creator-utils';
10
- import { readKsPatternConfigs, writeDemo, writeKsPatternConfig, readKsNavConfig, addKsNavItems } from '@knapsack/ks-file-utils';
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
4
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
5
+ }) : x)(function(x) {
6
+ if (typeof require !== "undefined") return require.apply(this, arguments);
7
+ throw Error('Dynamic require of "' + x + '" is not supported');
8
+ });
11
9
 
12
- var N=Object.defineProperty;var c=(r,e)=>N(r,"name",{value:e,configurable:!0}),K=(r=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(r,{get:(e,t)=>(typeof require<"u"?require:e)[t]}):r)(function(r){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+r+'" is not supported')});function ee({templateName:r,attributes:e,children:t}){return `
13
- <${r}
14
- ${e}
15
- ${t?`>
16
- ${t}
17
- </${r}>`:"/>"}
18
- `}c(ee,"renderUsageTemplate");var O="DemoApp";function te({imports:r="",children:e}){return `${r}
10
+ // ../../../../node_modules/.pnpm/tsup@8.2.4_@microsoft+api-extractor@7.43.8_@types+node@20.16.6__@swc+core@1.3.57_@swc+helpers_iqa4vqpgdlzwuubzthdmdz7nfe/node_modules/tsup/assets/esm_shims.js
11
+ import { fileURLToPath } from "url";
12
+ import path from "path";
13
+ var getFilename = /* @__PURE__ */ __name(() => fileURLToPath(import.meta.url), "getFilename");
14
+ var getDirname = /* @__PURE__ */ __name(() => path.dirname(getFilename()), "getDirname");
15
+ var __dirname = /* @__PURE__ */ getDirname();
19
16
 
20
- function ${O}() {
17
+ // src/renderer-react.ts
18
+ import sleep from "sleep-promise";
19
+ import {
20
+ RendererWebpackBase,
21
+ convertImportMapToNeededImportsByPath
22
+ } from "@knapsack/renderer-webpack-base";
23
+ import { pascalCase, isFirstLetterCapital } from "@knapsack/utils";
24
+ import { knapsackEvents, log as log2 } from "@knapsack/app";
25
+ import {
26
+ babelCodeForBrowser,
27
+ createSlotOptionsHtmlTags
28
+ } from "@knapsack/app/renderers";
29
+ import {
30
+ rendererIds
31
+ } from "@knapsack/types";
32
+ import {
33
+ exists as fileExists,
34
+ findUpPkgJson,
35
+ getJsExportNames as getJsExportNames2,
36
+ readFile as readFile2,
37
+ formatCode as formatCode2,
38
+ assertFileExists
39
+ } from "@knapsack/file-utils";
40
+ import { join, relative, parse, isAbsolute } from "path";
41
+
42
+ // src/utils.ts
43
+ import { log } from "@knapsack/app";
44
+ import {
45
+ getModulePkgJson,
46
+ readFile,
47
+ copy,
48
+ formatCode,
49
+ resolvePath,
50
+ findUp
51
+ } from "@knapsack/file-utils";
52
+ import { removeWrappingDoubleQuotes } from "@knapsack/utils";
53
+ import path2 from "path";
54
+ import { isNumberProp, isOptionsProp } from "@knapsack/types";
55
+ function renderUsageTemplate({
56
+ templateName,
57
+ attributes,
58
+ children
59
+ }) {
60
+ return `
61
+ <${templateName}
62
+ ${attributes}
63
+ ${children ? `>
64
+ ${children}
65
+ </${templateName}>` : "/>"}
66
+ `;
67
+ }
68
+ __name(renderUsageTemplate, "renderUsageTemplate");
69
+ var demoAppName = "DemoApp";
70
+ function renderDemoAppTemplate({
71
+ imports = "",
72
+ children
73
+ }) {
74
+ return `${imports}
75
+
76
+ function ${demoAppName}() {
21
77
  return (
22
- ${e}
78
+ ${children}
23
79
  )
24
80
  }
25
- `}c(te,"renderDemoAppTemplate");async function M(r){let e=Object.keys(r.props||{}).map(n=>{let p=r.props[n];return {key:n,value:p}}),{templateName:t,children:s,extraProps:a=[]}=r;if(!t)throw new Error('Cannot getUsage of a React Component when no "templateName" is provided.');let o=e.map(({key:n,value:p})=>{switch(typeof p){case"string":return p.startsWith("(")&&p.includes("=>")?`${n}={${p}}`:`${n}="${p}"`;case"boolean":return p?`${n}`:`${n}={${p}}`;default:return `${n}={${JSON.stringify(p)}}`}}),i=[],l={};a.forEach(({key:n,value:p})=>{l[n]=l[n]??[],l[n].push(p);}),Object.entries(l).forEach(([n,p])=>{let u=p.length===1?p[0]:`<>${p.join(`
26
- `)}</>`;i.push(`${n}={${u}}`);});let m=ee({templateName:t,attributes:[...o,...i].join(" "),children:s});return r.format?formatCode({contents:m,path:"x.tsx"}).then(n=>n.trim()).catch(()=>m.trim()):m.trim()}c(M,"getUsage");async function v({children:r,imports:e,format:t}){let s=te({children:r,imports:e});return t?formatCode({contents:s,path:"x.tsx"}):s}c(v,"getDemoAppUsage");async function J({src:r}){let e=await findUp("tsconfig.json",{cwd:h.dirname(r)}),t=await import('react-docgen-typescript'),s={shouldExtractLiteralValuesFromEnum:!0,savePropValueAsString:!0,skipChildrenPropWithoutDoc:!1,customComponentTypes:["VoidFunctionComponent","VFC"]};return {info:(e?t.withCustomConfig(e,s).parse:t.withDefaultConfig(s).parse)(r)}}c(J,"getTypeScriptInfoFromFile");function re({info:r,exportName:e}){try{if(!r)return !1;let t={props:{$schema:"http://json-schema.org/draft-07/schema",type:"object",required:[],properties:{}},slots:{}},a=!e||e==="default"?r.pop():r.find(i=>i.displayName===e);if(!a)return !1;return Object.entries(a?.props||{}).forEach(([i,l])=>{let{name:m,description:n,defaultValue:p,required:u,type:f,parent:y}=l;switch(f?.name?.replace("| undefined","").replace(/<.*/g,"").trim()){case"string":t.props.properties[i]={type:"string"};break;case"number":t.props.properties[i]={type:"number"};break;case"boolean":case"bool":p&&"value"in p&&(p.value=p.value==="true"),t.props.properties[i]={type:"boolean"};break;case"enum":t.props.properties[i]={type:"string",enum:[...new Set(f.value.map(({value:d})=>removeWrappingDoubleQuotes(d?.trim())).filter(Boolean))]};break;case"ReactNode":case"React.ReactNode":case"React.ReactElement":case"ReactElement":t.slots[i]={title:i},n&&(t.slots[i]={...t.slots[i],description:n});break;case"VFC":case"FC":t.slots[i]={title:i,description:n||"A reference to a component",isTemplateReference:!0,allowOnlyOne:!0,disallowText:!0};break;default:if(f?.name?.startsWith("("))t.props.properties[i]={typeof:"function",tsType:l?.type?.name};else if(f?.name?.includes("|")){let d=f.name.split("|").map(P=>removeWrappingDoubleQuotes(P.trim())).filter(Boolean);d?.length&&(t.props.properties[i]={type:"string",enum:[...new Set(d)]});}else t.props.properties[i]={tsType:l?.type?.name};}t.props.properties[i]&&(u&&t.props.required.push(i),n&&!t.props.properties[i].description&&(t.props.properties[i].description=n),p&&"value"in p&&(isNumberProp(t.props.properties[i])?t.props.properties[i].default=parseFloat(p.value):t.props.properties[i].default=removeWrappingDoubleQuotes(p.value)));}),t}catch(t){return log.verbose("Could not infer spec from React TypeScript file",{exportName:e,error:t},"react renderer"),!1}}c(re,"extractSpecFromTypeScriptInfo");async function se({src:r}){let e=await import('react-docgen'),{builtinResolvers:t}=e,s=await readFile(r),{FindExportedDefinitionsResolver:a}=t;return {info:e.parse(s,{resolver:new a,handlers:null,filename:r})}}c(se,"getPropTypesInfoFromFile");function ae({info:r,exportName:e}){try{let s=!e||e==="default"?r.pop():r.find(o=>o.displayName===e),a={isInferred:!0,props:{$schema:"http://json-schema.org/draft-07/schema",type:"object",required:[],properties:{}},slots:{}};return Object.entries(s?.props||{}).forEach(([o,i])=>{let{required:l,description:m,defaultValue:n}=i;switch(i?.type?.name){case"string":a.props.properties[o]={type:"string"};break;case"func":a.props.properties[o]={type:"string"};break;case"bool":a.props.properties[o]={type:"boolean"};break;case"node":a.slots[o]={title:o,description:m};}a.props.properties[o]&&(l&&a.props.required.push(o),m&&!a.props.properties[o].description&&(a.props.properties[o].description=m),n&&"value"in n&&(a.props.properties[o].default=typeof n.value=="string"?removeWrappingDoubleQuotes(n.value):n.value));}),a}catch(t){return log.verbose("Could not infer spec from React PropTypes",{exportName:e,error:t},"react renderer"),!1}}c(ae,"extractSpecFromPropTypesInfo");function ne({spec:r}){return r===!1||Object.entries(r?.props?.properties||{}).forEach(([e,t])=>{isOptionsProp(t)&&(t.enum.includes(t.default)||(t.default=void 0));}),r}c(ne,"cleanUpSpec");async function oe({src:r,resolveFromDir:e}){let t=await resolvePath({path:r,resolveFromDir:e,resolveType:"types"});if(t.exists){let o=await J({src:t.absolutePath});if(o)return {type:"typescript",info:o.info}}let s=await resolvePath({path:r,resolveFromDir:e});if(!s.exists)return {type:"unknown"};let{ext:a}=h.parse(s.absolutePath);switch(a){case".jsx":return {type:"propTypes",info:(await se({src:s.absolutePath})).info};case".ts":case".tsx":return {type:"typescript",info:(await J({src:s.absolutePath})).info};default:return {type:"unknown"}}}c(oe,"getReactModuleInfoUncached");var $=new Map,V=c(()=>{log.info("Clearing React TypeScript inferSpec cache..."),$.clear();},"clearInferSpecCache");async function ie(r){let e=JSON.stringify(r);return $.has(e)||$.set(e,oe(r)),$.get(e)}c(ie,"getReactModuleInfo");async function pe({src:r,exportName:e,resolveFromDir:t}){let s=await ie({src:r,resolveFromDir:t});switch(s.type){case"typescript":return re({info:s.info,exportName:e});case"propTypes":return ae({info:s.info,exportName:e});case"unknown":default:return !1}}c(pe,"getReactSpec");async function B(r){return ne({spec:await pe(r)})}c(B,"getReactDocs");async function L(r,e){try{let{version:t}=getModulePkgJson("react"),{version:s}=getModulePkgJson("react-dom"),a=h.dirname(K.resolve("react",{paths:[process.cwd()]})),o=h.dirname(K.resolve("react-dom",{paths:[process.cwd()]}));await Promise.all([copy(h.join(a,"umd/react.development.js"),h.join(r,`react.development.${t}.js`)),copy(h.join(a,"umd/react.production.min.js"),h.join(r,`react.production.min.${t}.js`)),copy(h.join(o,"umd/react-dom.production.min.js"),h.join(r,`react-dom.production.min.${s}.js`)),copy(h.join(o,"umd/react-dom.development.js"),h.join(r,`react-dom.development.${s}.js`))]);let i=process.env.NODE_ENV==="production"?"production.min":"development";return [h.join(e,`react.${i}.${t}.js`),h.join(e,`react-dom.${i}.${s}.js`)]}catch(t){log.warn('Error trying to copy "react" and "react-dom" JS files, are they installed? We want to use your exact versions.',t,"templateRenderer:react"),process.exit(1);}}c(L,"copyReactAssets");function ye(r){return r.toUpperCase()===r}c(ye,"isCapitalLetter");function we(r){return ye(r[0])}c(we,"startsWithCapitalLetter");function Pe({importName:r,id:e,title:t=r,pkgPath:s,initialDemoId:a}){return {id:e,title:t,description:"",statuses:{main:"ready"},templates:[{id:"react",title:"react",path:s,alias:r,templateLanguageId:"react",spec:{isInferred:!0},demoIds:[a],blockIds:[]}],tabs:[{type:"template",id:"react"}],subPages:[]}}c(Pe,"createPatternData");var G=createCreator({id:"react-patterns",title:"React Ks Patterns",description:"Adds React templates as Knapsack Patterns",getQuestions:c(async()=>({pkgPath:{type:"text",title:"Package path"},importPrefix:{type:"text",title:"Import Prefix to Remove"}}),"getQuestions"),getTasks:c(async({answers:{pkgPath:r,importPrefix:e=""},config:t})=>{let s=t.dest,o=(await readKsPatternConfigs({dataDir:s})).reduce((l,m)=>{let n=m.templates?.filter(p=>p.templateLanguageId==="react")??[];return l.push(...n.map(p=>p.alias)),l},[]),{exports:i}=await getJsExportNames({path:r});return [{title:"Pick Imports to add",task:c((l,m)=>tasks.runSubCreator({task:m,config:t,creator:createCreator({id:"react-pattern-import-names",getQuestions:c(async()=>({importNames:{type:"choices",choices:i.filter(n=>we(n)&&!o.includes(n)).map(n=>({value:n}))}}),"getQuestions"),getTasks:c(async({answers:{importNames:n}})=>{let p=n.map(u=>({importName:u,patternId:u.startsWith(e)?u.slice(e.length).toLowerCase():u.toLowerCase()}));return [...p.map(({importName:u,patternId:f})=>({title:`Add ${u} React Template`,task:c(async(y,R)=>{let d={type:"data",id:makeShortId(),title:"Main",patternId:f,templateId:"react",data:{props:{},slots:{}}},P=Pe({id:f,importName:u,pkgPath:r,initialDemoId:d.id});await Promise.all([writeDemo({dataDir:s,demo:d}),writeKsPatternConfig({dataDir:s,patternId:f,data:P})]);},"task")})),{title:"Updating Nav",task:c(async(u,f)=>{let{byId:y}=await readKsNavConfig({dataDir:s}),R=Object.values(y).find(({path:d,name:P,id:w})=>d?!1:P.toLowerCase()==="patterns"||P.toLowerCase()==="components");await addKsNavItems({dataDir:s,navItems:p.map(({patternId:d})=>({navId:d,navPath:`/pattern/${d}`,navParent:R?.id||"root"}))});},"task")}]},"getTasks")})}),"task")}]},"getTasks")});var H="ks-react-meta";var{pkg:j}=findUpPkgJson(__dirname);log.setupUpdateNotifier({...j,name:j.name,version:j.version});var Q=class r extends RendererWebpackBase{static{c(this,"KnapsackReactRenderer");}assets;babelConfig;demoWrapperPath;disableReactStrictMode;constructor({webpackConfig:e,demoWrapperPath:t=join(__dirname,"./demo-wrapper.mjs"),id:s=rendererIds.react,disableReactStrictMode:a}={}){super({id:s,extension:".jsx",language:"jsx",webpackConfig:e,extraScripts:["@knapsack/renderer-react/client"]}),this.language="jsx",this.assets=[],this.demoWrapperPath=t,this.disableReactStrictMode=a,this.creators=[G];}init=c(async e=>{if(await super.init(e),this.assets=await L(this.outputDir,this.publicPath),!await exists(this.demoWrapperPath))throw new Error(`Could not find demo wrapper at: "${this.demoWrapperPath}"`)},"init");getMeta=c(()=>({id:this.id,title:"React",aliasUse:"optional",aliasTitle:"Named Export",aliasIsJsNamedExport:!0,aliasDescription:"If `export X` was used instead of `export default`, then provide X.",enableDataDemos:!0,enableTemplateDemos:!0,hasSlotsSupport:!0,hasSlotOptionsSupport:!0,version:j.version,hasInferSpecSupport:!0,syntaxHighlightingLanguage:"jsx",hasTemplateSuggestionsSupport:!0,prototypingTemplate:{path:"@knapsack/renderer-react/prototype-template",spec:{isInferred:!1,props:{type:"object",properties:{}},slots:{children:{title:"Children"}}}}}),"getMeta");changeCase=c(e=>pascalCase(e),"changeCase");createWebpackConfig=c(()=>{let e=super.createWebpackConfig();return e.externals={react:"React","react-dom":"ReactDOM"},e},"createWebpackConfig");getJsImports=c(()=>{let e=super.getJsImports();return e.push({type:"extra",importInfo:{type:"default",path:this.demoWrapperPath,name:"DemoWrapper"}},{type:"extra",importInfo:{type:"default",path:join(__dirname,"./error-catcher.mjs"),name:"ErrorCatcher"}}),e},"getJsImports");async prepClientRenderResults({usage:e,demoApp:t,imports:s,renderOptions:{pattern:a,template:o,demo:i}}){let l=this.getJsImports().filter(d=>d.type==="extra"),{imports:m,isDeclaredVarsUnique:n,nameCollisions:p}=this.makeKsJsImportsUnique({imports:[...s,...l]});n||log.error(`${p.join(", ")} are declared multiple times`,{imports:m});let u={demo:i,disableReactStrictMode:this.disableReactStrictMode,neededImports:m,demoWrapperProps:{pattern:a,template:o,demo:i,patternsUsed:m.flatMap(d=>d.type==="pattern-template"?[{patternId:d.patternId,templateId:d.templateId}]:d.type==="pattern-template-demo"?[{patternId:d.patternId,templateId:d.templateId,demoId:d.demoId}]:[])}},f=`
81
+ `;
82
+ }
83
+ __name(renderDemoAppTemplate, "renderDemoAppTemplate");
84
+ async function getUsage(data) {
85
+ const props = Object.keys(data.props || {}).map((key) => {
86
+ const value = data.props[key];
87
+ return {
88
+ key,
89
+ value
90
+ };
91
+ });
92
+ const { templateName, children, extraProps = [] } = data;
93
+ if (!templateName) {
94
+ throw new Error(
95
+ `Cannot getUsage of a React Component when no "templateName" is provided.`
96
+ );
97
+ }
98
+ const attributes = props.map(({ key, value }) => {
99
+ switch (typeof value) {
100
+ case "string":
101
+ if (value.startsWith("(") && value.includes("=>")) {
102
+ return `${key}={${value}}`;
103
+ }
104
+ return `${key}="${value}"`;
105
+ case "boolean":
106
+ return value ? `${key}` : `${key}={${value}}`;
107
+ default:
108
+ return `${key}={${JSON.stringify(value)}}`;
109
+ }
110
+ });
111
+ const extraAttributes = [];
112
+ const slotProps = {};
113
+ extraProps.forEach(({ key, value }) => {
114
+ slotProps[key] = slotProps[key] ?? [];
115
+ slotProps[key].push(value);
116
+ });
117
+ Object.entries(slotProps).forEach(([key, values]) => {
118
+ const value = values.length === 1 ? values[0] : `<>${values.join("\n")}</>`;
119
+ extraAttributes.push(`${key}={${value}}`);
120
+ });
121
+ const result = renderUsageTemplate({
122
+ templateName,
123
+ attributes: [...attributes, ...extraAttributes].join(" "),
124
+ children
125
+ });
126
+ return data.format ? formatCode({
127
+ contents: result,
128
+ path: "x.tsx"
129
+ // doing this to set format language
130
+ }).then((code) => code.trim()).catch(() => result.trim()) : result.trim();
131
+ }
132
+ __name(getUsage, "getUsage");
133
+ async function getDemoAppUsage({
134
+ children,
135
+ imports,
136
+ format
137
+ }) {
138
+ const code = renderDemoAppTemplate({
139
+ children,
140
+ imports
141
+ });
142
+ if (!format) return code;
143
+ return formatCode({
144
+ contents: code,
145
+ path: "x.tsx"
146
+ // doing this to set format language
147
+ });
148
+ }
149
+ __name(getDemoAppUsage, "getDemoAppUsage");
150
+ async function getTypeScriptInfoFromFile({ src }) {
151
+ const tsConfigPath = await findUp("tsconfig.json", {
152
+ cwd: path2.dirname(src)
153
+ });
154
+ const rdTs = await import("react-docgen-typescript");
155
+ const config = {
156
+ shouldExtractLiteralValuesFromEnum: true,
157
+ savePropValueAsString: true,
158
+ skipChildrenPropWithoutDoc: false,
159
+ // In addition to the ones listed here, which had not strangely included these below ~ https://github.com/styleguidist/react-docgen-typescript/blob/287e7012843cb26fed8f4bd8ee24e462c25a1414/src/parser.ts#L308
160
+ customComponentTypes: ["VoidFunctionComponent", "VFC"]
161
+ };
162
+ const parse2 = tsConfigPath ? rdTs.withCustomConfig(tsConfigPath, config).parse : rdTs.withDefaultConfig(config).parse;
163
+ return {
164
+ info: parse2(src)
165
+ };
166
+ }
167
+ __name(getTypeScriptInfoFromFile, "getTypeScriptInfoFromFile");
168
+ function extractSpecFromTypeScriptInfo({
169
+ info: results,
170
+ exportName
171
+ }) {
172
+ try {
173
+ if (!results) return false;
174
+ const spec = {
175
+ props: {
176
+ $schema: "http://json-schema.org/draft-07/schema",
177
+ type: "object",
178
+ required: [],
179
+ properties: {}
180
+ },
181
+ slots: {
182
+ // children: {
183
+ // title: 'children',
184
+ // },
185
+ }
186
+ };
187
+ const isDefaultExport = !exportName || exportName === "default";
188
+ const result = isDefaultExport ? results.pop() : results.find((r) => r.displayName === exportName);
189
+ if (!result) return false;
190
+ const { displayName } = result;
191
+ Object.entries(result?.props || {}).forEach(([propName, propDef]) => {
192
+ const { name, description, defaultValue, required, type, parent } = propDef;
193
+ const propType = type?.name?.replace("| undefined", "").replace(/<.*/g, "").trim();
194
+ switch (propType) {
195
+ case "string":
196
+ spec.props.properties[propName] = {
197
+ type: "string"
198
+ };
199
+ break;
200
+ case "number":
201
+ spec.props.properties[propName] = {
202
+ type: "number"
203
+ };
204
+ break;
205
+ case "boolean":
206
+ case "bool":
207
+ if (defaultValue && "value" in defaultValue) {
208
+ defaultValue.value = defaultValue.value === "true";
209
+ }
210
+ spec.props.properties[propName] = {
211
+ type: "boolean"
212
+ };
213
+ break;
214
+ case "enum":
215
+ spec.props.properties[propName] = {
216
+ type: "string",
217
+ // yes there is a double "value" & yes it is confusing
218
+ enum: [
219
+ // ensure list is unique
220
+ ...new Set(
221
+ type.value.map(({ value }) => removeWrappingDoubleQuotes(value?.trim())).filter(Boolean)
222
+ )
223
+ ]
224
+ };
225
+ break;
226
+ case "ReactNode":
227
+ case "React.ReactNode":
228
+ case "React.ReactElement":
229
+ case "ReactElement":
230
+ spec.slots[propName] = {
231
+ title: propName
232
+ };
233
+ if (description) {
234
+ spec.slots[propName] = {
235
+ ...spec.slots[propName],
236
+ description
237
+ };
238
+ }
239
+ break;
240
+ case "VFC":
241
+ case "FC":
242
+ spec.slots[propName] = {
243
+ title: propName,
244
+ description: description || "A reference to a component",
245
+ isTemplateReference: true,
246
+ allowOnlyOne: true,
247
+ disallowText: true
248
+ };
249
+ break;
250
+ default: {
251
+ if (type?.name?.startsWith("(")) {
252
+ spec.props.properties[propName] = {
253
+ // description: `\`${type.name}\` ${description}`,
254
+ typeof: "function",
255
+ tsType: propDef?.type?.name
256
+ };
257
+ } else if (type?.name?.includes("|")) {
258
+ const options = type.name.split("|").map((enumItem) => removeWrappingDoubleQuotes(enumItem.trim())).filter(Boolean);
259
+ if (options?.length) {
260
+ spec.props.properties[propName] = {
261
+ type: "string",
262
+ // ensuring list is unique
263
+ enum: [...new Set(options)]
264
+ };
265
+ }
266
+ } else {
267
+ spec.props.properties[propName] = {
268
+ tsType: propDef?.type?.name
269
+ };
270
+ }
271
+ }
272
+ }
273
+ if (spec.props.properties[propName]) {
274
+ if (required) spec.props.required.push(propName);
275
+ if (description && !spec.props.properties[propName].description) {
276
+ spec.props.properties[propName].description = description;
277
+ }
278
+ if (defaultValue && "value" in defaultValue) {
279
+ if (isNumberProp(spec.props.properties[propName])) {
280
+ spec.props.properties[propName].default = parseFloat(
281
+ defaultValue.value
282
+ );
283
+ } else {
284
+ spec.props.properties[propName].default = removeWrappingDoubleQuotes(defaultValue.value);
285
+ }
286
+ }
287
+ }
288
+ });
289
+ return spec;
290
+ } catch (error) {
291
+ log.verbose(
292
+ "Could not infer spec from React TypeScript file",
293
+ {
294
+ exportName,
295
+ error
296
+ },
297
+ "react renderer"
298
+ );
299
+ return false;
300
+ }
301
+ }
302
+ __name(extractSpecFromTypeScriptInfo, "extractSpecFromTypeScriptInfo");
303
+ async function getPropTypesInfoFromFile({ src }) {
304
+ const reactDocs = await import("react-docgen");
305
+ const { builtinResolvers } = reactDocs;
306
+ const fileSrc = await readFile(src);
307
+ const { FindExportedDefinitionsResolver } = builtinResolvers;
308
+ const results = reactDocs.parse(fileSrc, {
309
+ resolver: new FindExportedDefinitionsResolver(),
310
+ handlers: null,
311
+ filename: src
312
+ // babelrc: false,
313
+ });
314
+ return {
315
+ info: results
316
+ };
317
+ }
318
+ __name(getPropTypesInfoFromFile, "getPropTypesInfoFromFile");
319
+ function extractSpecFromPropTypesInfo({
320
+ info: results,
321
+ exportName
322
+ }) {
323
+ try {
324
+ const isDefaultExport = !exportName || exportName === "default";
325
+ const result = isDefaultExport ? results.pop() : results.find((r) => r.displayName === exportName);
326
+ const spec = {
327
+ isInferred: true,
328
+ props: {
329
+ $schema: "http://json-schema.org/draft-07/schema",
330
+ type: "object",
331
+ required: [],
332
+ properties: {}
333
+ },
334
+ slots: {}
335
+ };
336
+ Object.entries(result?.props || {}).forEach(([propName, propDef]) => {
337
+ const { required, description, defaultValue } = propDef;
338
+ switch (propDef?.type?.name) {
339
+ case "string":
340
+ spec.props.properties[propName] = {
341
+ type: "string"
342
+ };
343
+ break;
344
+ case "func":
345
+ spec.props.properties[propName] = {
346
+ type: "string"
347
+ };
348
+ break;
349
+ case "bool":
350
+ spec.props.properties[propName] = {
351
+ type: "boolean"
352
+ };
353
+ break;
354
+ case "node":
355
+ spec.slots[propName] = {
356
+ title: propName,
357
+ description
358
+ };
359
+ }
360
+ if (spec.props.properties[propName]) {
361
+ if (required) spec.props.required.push(propName);
362
+ if (description && !spec.props.properties[propName].description) {
363
+ spec.props.properties[propName].description = description;
364
+ }
365
+ if (defaultValue && "value" in defaultValue) {
366
+ spec.props.properties[propName].default = typeof defaultValue.value === "string" ? removeWrappingDoubleQuotes(defaultValue.value) : defaultValue.value;
367
+ }
368
+ }
369
+ });
370
+ return spec;
371
+ } catch (error) {
372
+ log.verbose(
373
+ "Could not infer spec from React PropTypes",
374
+ {
375
+ exportName,
376
+ error
377
+ },
378
+ "react renderer"
379
+ );
380
+ return false;
381
+ }
382
+ }
383
+ __name(extractSpecFromPropTypesInfo, "extractSpecFromPropTypesInfo");
384
+ function cleanUpSpec({
385
+ spec
386
+ }) {
387
+ if (spec === false) return spec;
388
+ Object.entries(spec?.props?.properties || {}).forEach(([propName, prop]) => {
389
+ if (isOptionsProp(prop)) {
390
+ if (!prop.enum.includes(prop.default)) {
391
+ prop.default = void 0;
392
+ }
393
+ }
394
+ });
395
+ return spec;
396
+ }
397
+ __name(cleanUpSpec, "cleanUpSpec");
398
+ async function getReactModuleInfoUncached({
399
+ src: unknownSrc,
400
+ resolveFromDir
401
+ }) {
402
+ const typesInfo = await resolvePath({
403
+ path: unknownSrc,
404
+ resolveFromDir,
405
+ resolveType: "types"
406
+ });
407
+ if (typesInfo.exists) {
408
+ const typeScriptInfo = await getTypeScriptInfoFromFile({
409
+ src: typesInfo.absolutePath
410
+ });
411
+ if (typeScriptInfo) {
412
+ return {
413
+ type: "typescript",
414
+ info: typeScriptInfo.info
415
+ };
416
+ }
417
+ }
418
+ const jsInfo = await resolvePath({
419
+ path: unknownSrc,
420
+ resolveFromDir
421
+ });
422
+ if (!jsInfo.exists) return { type: "unknown" };
423
+ const { ext } = path2.parse(jsInfo.absolutePath);
424
+ switch (ext) {
425
+ case ".jsx": {
426
+ const propTypesInfo = await getPropTypesInfoFromFile({
427
+ src: jsInfo.absolutePath
428
+ });
429
+ return {
430
+ type: "propTypes",
431
+ info: propTypesInfo.info
432
+ };
433
+ }
434
+ case ".ts":
435
+ case ".tsx": {
436
+ const typeScriptInfo = await getTypeScriptInfoFromFile({
437
+ src: jsInfo.absolutePath
438
+ });
439
+ return {
440
+ type: "typescript",
441
+ info: typeScriptInfo.info
442
+ };
443
+ }
444
+ default:
445
+ return {
446
+ type: "unknown"
447
+ };
448
+ }
449
+ }
450
+ __name(getReactModuleInfoUncached, "getReactModuleInfoUncached");
451
+ var getReactModuleInfoCache = /* @__PURE__ */ new Map();
452
+ var clearInferSpecCache = /* @__PURE__ */ __name(() => {
453
+ log.info(`Clearing React TypeScript inferSpec cache...`);
454
+ getReactModuleInfoCache.clear();
455
+ }, "clearInferSpecCache");
456
+ async function getReactModuleInfo(args) {
457
+ const cacheKey = JSON.stringify(args);
458
+ if (!getReactModuleInfoCache.has(cacheKey)) {
459
+ getReactModuleInfoCache.set(cacheKey, getReactModuleInfoUncached(args));
460
+ }
461
+ return getReactModuleInfoCache.get(cacheKey);
462
+ }
463
+ __name(getReactModuleInfo, "getReactModuleInfo");
464
+ async function getReactSpec({
465
+ src,
466
+ exportName,
467
+ resolveFromDir
468
+ }) {
469
+ const reactModuleInfo = await getReactModuleInfo({
470
+ src,
471
+ resolveFromDir
472
+ });
473
+ switch (reactModuleInfo.type) {
474
+ case "typescript":
475
+ return extractSpecFromTypeScriptInfo({
476
+ info: reactModuleInfo.info,
477
+ exportName
478
+ });
479
+ case "propTypes":
480
+ return extractSpecFromPropTypesInfo({
481
+ info: reactModuleInfo.info,
482
+ exportName
483
+ });
484
+ case "unknown":
485
+ default:
486
+ return false;
487
+ }
488
+ }
489
+ __name(getReactSpec, "getReactSpec");
490
+ async function getReactDocs(opt) {
491
+ return cleanUpSpec({
492
+ spec: await getReactSpec(opt)
493
+ });
494
+ }
495
+ __name(getReactDocs, "getReactDocs");
496
+ async function copyReactAssets(distDirAbsolute, publicPath) {
497
+ try {
498
+ const { version: reactVersion } = getModulePkgJson("react");
499
+ const { version: reactDomVersion } = getModulePkgJson("react-dom");
500
+ const reactRoot = path2.dirname(
501
+ __require.resolve("react", {
502
+ paths: [process.cwd()]
503
+ })
504
+ );
505
+ const reactDomRoot = path2.dirname(
506
+ __require.resolve("react-dom", {
507
+ paths: [process.cwd()]
508
+ })
509
+ );
510
+ await Promise.all([
511
+ copy(
512
+ path2.join(reactRoot, "umd/react.development.js"),
513
+ path2.join(distDirAbsolute, `react.development.${reactVersion}.js`)
514
+ ),
515
+ copy(
516
+ path2.join(reactRoot, "umd/react.production.min.js"),
517
+ path2.join(distDirAbsolute, `react.production.min.${reactVersion}.js`)
518
+ ),
519
+ copy(
520
+ path2.join(reactDomRoot, "umd/react-dom.production.min.js"),
521
+ path2.join(
522
+ distDirAbsolute,
523
+ `react-dom.production.min.${reactDomVersion}.js`
524
+ )
525
+ ),
526
+ copy(
527
+ path2.join(reactDomRoot, "umd/react-dom.development.js"),
528
+ path2.join(
529
+ distDirAbsolute,
530
+ `react-dom.development.${reactDomVersion}.js`
531
+ )
532
+ )
533
+ ]);
534
+ const reactFileSuffix = process.env.NODE_ENV === "production" ? "production.min" : "development";
535
+ return [
536
+ path2.join(publicPath, `react.${reactFileSuffix}.${reactVersion}.js`),
537
+ path2.join(
538
+ publicPath,
539
+ `react-dom.${reactFileSuffix}.${reactDomVersion}.js`
540
+ )
541
+ ];
542
+ } catch (error) {
543
+ log.warn(
544
+ 'Error trying to copy "react" and "react-dom" JS files, are they installed? We want to use your exact versions.',
545
+ error,
546
+ "templateRenderer:react"
547
+ );
548
+ process.exit(1);
549
+ }
550
+ }
551
+ __name(copyReactAssets, "copyReactAssets");
552
+
553
+ // src/react-creators.ts
554
+ import { getJsExportNames } from "@knapsack/file-utils";
555
+ import { createCreator, tasks } from "@knapsack/creator-utils";
556
+ import {
557
+ readKsPatternConfigs,
558
+ writeKsPatternConfig,
559
+ readKsNavConfig,
560
+ addKsNavItems,
561
+ writeDemo
562
+ } from "@knapsack/ks-file-utils";
563
+ import { makeShortId } from "@knapsack/utils";
564
+ function isCapitalLetter(char) {
565
+ return char.toUpperCase() === char;
566
+ }
567
+ __name(isCapitalLetter, "isCapitalLetter");
568
+ function startsWithCapitalLetter(str) {
569
+ return isCapitalLetter(str[0]);
570
+ }
571
+ __name(startsWithCapitalLetter, "startsWithCapitalLetter");
572
+ function createPatternData({
573
+ importName,
574
+ id,
575
+ title = importName,
576
+ pkgPath,
577
+ initialDemoId
578
+ }) {
579
+ return {
580
+ id,
581
+ title,
582
+ description: "",
583
+ statuses: {
584
+ main: "ready"
585
+ },
586
+ templates: [
587
+ {
588
+ id: "react",
589
+ title: "react",
590
+ path: pkgPath,
591
+ alias: importName,
592
+ templateLanguageId: "react",
593
+ spec: {
594
+ isInferred: true
595
+ },
596
+ demoIds: [initialDemoId],
597
+ blockIds: []
598
+ }
599
+ ],
600
+ tabs: [
601
+ {
602
+ type: "template",
603
+ id: "react"
604
+ }
605
+ ],
606
+ subPages: []
607
+ };
608
+ }
609
+ __name(createPatternData, "createPatternData");
610
+ var createReactPattern = createCreator({
611
+ id: "react-patterns",
612
+ title: "React Ks Patterns",
613
+ description: "Adds React templates as Knapsack Patterns",
614
+ getQuestions: /* @__PURE__ */ __name(async () => ({
615
+ pkgPath: {
616
+ type: "text",
617
+ title: "Package path"
618
+ },
619
+ importPrefix: {
620
+ type: "text",
621
+ title: "Import Prefix to Remove"
622
+ }
623
+ }), "getQuestions"),
624
+ getTasks: /* @__PURE__ */ __name(async ({ answers: { pkgPath, importPrefix = "" }, config }) => {
625
+ const dataDir = config.dest;
626
+ const currentPatterns = await readKsPatternConfigs({
627
+ dataDir
628
+ });
629
+ const currentReactPatternsImportNames = currentPatterns.reduce(
630
+ (cur, pattern) => {
631
+ const reactTemplates = pattern.templates?.filter((t) => t.templateLanguageId === "react") ?? [];
632
+ cur.push(...reactTemplates.map((t) => t.alias));
633
+ return cur;
634
+ },
635
+ []
636
+ );
637
+ const { exports: allImports } = await getJsExportNames({
638
+ path: pkgPath
639
+ });
640
+ return [
641
+ {
642
+ title: "Pick Imports to add",
643
+ task: /* @__PURE__ */ __name((_, task) => tasks.runSubCreator({
644
+ task,
645
+ config,
646
+ creator: createCreator({
647
+ id: "react-pattern-import-names",
648
+ getQuestions: /* @__PURE__ */ __name(async () => ({
649
+ importNames: {
650
+ type: "choices",
651
+ choices: allImports.filter(
652
+ (importName) => startsWithCapitalLetter(importName) && !currentReactPatternsImportNames.includes(importName)
653
+ ).map((importName) => ({
654
+ value: importName
655
+ }))
656
+ }
657
+ }), "getQuestions"),
658
+ getTasks: /* @__PURE__ */ __name(async ({ answers: { importNames } }) => {
659
+ const patterns = importNames.map((importName) => ({
660
+ importName,
661
+ patternId: importName.startsWith(importPrefix) ? importName.slice(importPrefix.length).toLowerCase() : importName.toLowerCase()
662
+ }));
663
+ return [
664
+ ...patterns.map(
665
+ ({ importName, patternId }) => ({
666
+ title: `Add ${importName} React Template`,
667
+ task: /* @__PURE__ */ __name(async (__, subTask) => {
668
+ const initialDemo = {
669
+ type: "data",
670
+ id: makeShortId(),
671
+ title: "Main",
672
+ patternId,
673
+ templateId: "react",
674
+ data: {
675
+ props: {},
676
+ slots: {}
677
+ }
678
+ };
679
+ const pattern = createPatternData({
680
+ id: patternId,
681
+ importName,
682
+ pkgPath,
683
+ initialDemoId: initialDemo.id
684
+ });
685
+ await Promise.all([
686
+ writeDemo({
687
+ dataDir,
688
+ demo: initialDemo
689
+ }),
690
+ writeKsPatternConfig({
691
+ dataDir,
692
+ patternId,
693
+ data: pattern
694
+ })
695
+ ]);
696
+ }, "task")
697
+ })
698
+ ),
699
+ {
700
+ title: `Updating Nav`,
701
+ task: /* @__PURE__ */ __name(async (__, subTask) => {
702
+ const { byId } = await readKsNavConfig({
703
+ dataDir
704
+ });
705
+ const componentsGroup = Object.values(byId).find(
706
+ ({ path: path3, name, id }) => {
707
+ if (path3) return false;
708
+ if (name.toLowerCase() === "patterns") return true;
709
+ if (name.toLowerCase() === "components") return true;
710
+ return false;
711
+ }
712
+ );
713
+ await addKsNavItems({
714
+ dataDir,
715
+ navItems: patterns.map(({ patternId }) => ({
716
+ navId: patternId,
717
+ navPath: `/pattern/${patternId}`,
718
+ navParent: componentsGroup?.id || "root"
719
+ }))
720
+ });
721
+ }, "task")
722
+ }
723
+ ];
724
+ }, "getTasks")
725
+ })
726
+ }), "task")
727
+ }
728
+ ];
729
+ }, "getTasks")
730
+ });
731
+
732
+ // src/types.ts
733
+ var rendererMetaScriptTagId = "ks-react-meta";
734
+
735
+ // src/renderer-react.ts
736
+ var { pkg } = findUpPkgJson(__dirname);
737
+ log2.setupUpdateNotifier({ ...pkg, name: pkg.name, version: pkg.version });
738
+ var errorCatcherPath = join(__dirname, "./error-catcher.mjs");
739
+ var KnapsackReactRenderer = class _KnapsackReactRenderer extends RendererWebpackBase {
740
+ static {
741
+ __name(this, "KnapsackReactRenderer");
742
+ }
743
+ /**
744
+ * `react.js` & `react-dom.js` root relative paths
745
+ */
746
+ assets;
747
+ babelConfig;
748
+ demoWrapperPath;
749
+ disableReactStrictMode;
750
+ constructor({
751
+ webpackConfig,
752
+ demoWrapperPath = join(__dirname, "./demo-wrapper.mjs"),
753
+ id = rendererIds.react,
754
+ disableReactStrictMode
755
+ } = {}) {
756
+ super({
757
+ id,
758
+ language: "jsx",
759
+ webpackConfig,
760
+ extraScripts: [
761
+ // this is the code in `./client/init.mts`
762
+ "@knapsack/renderer-react/client"
763
+ ],
764
+ codeSrcs: [demoWrapperPath, errorCatcherPath]
765
+ });
766
+ this.language = "jsx";
767
+ this.assets = [];
768
+ this.demoWrapperPath = isAbsolute(demoWrapperPath) ? demoWrapperPath : this.resolvePathSync({
769
+ path: demoWrapperPath,
770
+ resolveFromDir: this.userConfigDir
771
+ }).absolutePath;
772
+ assertFileExists(
773
+ this.demoWrapperPath,
774
+ `Could not find demo wrapper at: "${this.demoWrapperPath}"
775
+ Please adjust setting in "knapsack.config.js" or pass a different path when creating the React Renderer.`
776
+ );
777
+ this.disableReactStrictMode = disableReactStrictMode;
778
+ this.creators = [createReactPattern];
779
+ }
780
+ init = /* @__PURE__ */ __name(async () => {
781
+ this.assets = await copyReactAssets(this.outputDir, this.publicPath);
782
+ if (!await fileExists(this.demoWrapperPath)) {
783
+ throw new Error(
784
+ `Could not find demo wrapper at: "${this.demoWrapperPath}"`
785
+ );
786
+ }
787
+ }, "init");
788
+ hydrate = /* @__PURE__ */ __name(async (opt) => {
789
+ await super.hydrate(opt);
790
+ await this.init({ missingFileVerbosity: "silent" });
791
+ }, "hydrate");
792
+ getMeta = /* @__PURE__ */ __name(() => ({
793
+ id: this.id,
794
+ title: "React",
795
+ aliasUse: "optional",
796
+ aliasTitle: "Named Export",
797
+ aliasIsJsNamedExport: true,
798
+ aliasDescription: "If `export X` was used instead of `export default`, then provide X.",
799
+ enableDataDemos: true,
800
+ enableTemplateDemos: true,
801
+ hasSlotsSupport: true,
802
+ hasSlotOptionsSupport: true,
803
+ version: pkg.version,
804
+ hasInferSpecSupport: true,
805
+ syntaxHighlightingLanguage: "jsx",
806
+ hasTemplateSuggestionsSupport: true,
807
+ prototypingTemplate: {
808
+ path: "@knapsack/renderer-react/prototype-template",
809
+ spec: {
810
+ isInferred: false,
811
+ props: {
812
+ type: "object",
813
+ properties: {}
814
+ },
815
+ slots: {
816
+ children: { title: "Children" }
817
+ }
818
+ }
819
+ }
820
+ }), "getMeta");
821
+ changeCase = /* @__PURE__ */ __name((str) => pascalCase(str), "changeCase");
822
+ createWebpackConfig = /* @__PURE__ */ __name(() => {
823
+ const config = super.createWebpackConfig();
824
+ config.externals = {
825
+ react: "React",
826
+ "react-dom": "ReactDOM"
827
+ };
828
+ return config;
829
+ }, "createWebpackConfig");
830
+ async prepClientRenderResults({
831
+ usage,
832
+ demoApp,
833
+ importMap,
834
+ renderOptions: { demo, state, patternId, templateId }
835
+ }) {
836
+ const meta = {
837
+ demo,
838
+ disableReactStrictMode: this.disableReactStrictMode,
839
+ neededImportsByPath: convertImportMapToNeededImportsByPath(importMap),
840
+ extraImports: {
841
+ DemoWrapper: {
842
+ type: "default",
843
+ path: this.demoWrapperPath,
844
+ name: "DemoWrapper"
845
+ },
846
+ ErrorCatcher: {
847
+ type: "default",
848
+ path: errorCatcherPath,
849
+ name: "ErrorCatcher"
850
+ }
851
+ },
852
+ demoWrapperProps: {
853
+ patternId,
854
+ templateId,
855
+ demo
856
+ }
857
+ };
858
+ let code = `
27
859
  window.knapsack = window.knapsack || {};
28
- window.knapsack.getDemoApp = ({ ${m.map(d=>d.importInfo.name).join(", ")} }) => {
29
- ${t}
30
- return ${O}
860
+ window.knapsack.getDemoApp = ({ ${[...importMap.keys()].join(", ")} }) => {
861
+ ${demoApp}
862
+ return ${demoAppName}
31
863
  }
32
- `,y="";try{f=await babelCodeForBrowser({code:f});}catch(d){console.log(f),console.log("---original code before babel error ^---"),console.trace(d.message),f=`console.error(${JSON.stringify(d.message)});`,y=`<pre><code>${d.message}</code></pre>`;}let R=`
33
- <script type="application/json" id="${H}">${JSON.stringify(u)}</script>
34
- <script type="application/javascript">${f}</script>
864
+ `;
865
+ let errorHtmlMsg = "";
866
+ try {
867
+ code = await babelCodeForBrowser({ code });
868
+ } catch (e) {
869
+ console.log(code);
870
+ console.log("---original code before babel error ^---");
871
+ console.trace(e.message);
872
+ code = `console.error(${JSON.stringify(e.message)});`;
873
+ errorHtmlMsg = `<pre><code>${e.message}</code></pre>`;
874
+ }
875
+ const html = `
876
+ <script type="application/json" id="${rendererMetaScriptTagId}">${JSON.stringify(
877
+ meta
878
+ )}</script>
879
+ <script type="application/javascript">${code}</script>
35
880
  <div id="render-root" class="knapsack-pattern-direct-parent" data-dev-note="Knapsack React Template Wrapper"></div>
36
- ${this.assets.map(d=>`<script src="${d}"></script>`).join(`
37
- `)}
38
- ${this.createHtmlTagsForAssetPaths({assets:this.getWebpackAssetPaths(),scriptTagsAreAsync:!1})}
39
- ${y}
40
- `;return {ok:!y,html:await formatCode({contents:R,path:"x.html"}),usage:e,templateLanguage:this.language}}render=c(async e=>{if(e.demo?.type==="template"){let t=[5,10,20,50,100,1e3,1e3],s,a=0;for(;;)try{let{absolutePath:p,exists:u}=await this.resolvePath(e.demo.templateInfo.path);if(!u)throw new Error(`Template demo file does not exist: ${p}`);s=p;break}catch(p){let u=t[a];if(!u)throw new Error(p);a+=1,await Ie(u);}let[o,{usage:i,imports:l}]=await Promise.all([readFile(s),this.getUsageAndImports(e)]),m=await v({children:i});return await this.prepClientRenderResults({usage:o,demoApp:m,imports:l,renderOptions:e})}if(e.demo?.type==="data"){let{usage:t,imports:s}=await this.getUsageAndImports(e),{code:a}=this.createJsImportCodeBlock({imports:s}),[o,i]=await Promise.all([v({children:t,imports:a,format:!0}),v({children:t})]);return this.prepClientRenderResults({demoApp:i,usage:o,imports:s,renderOptions:e})}},"render");getUsageAndImports=c(async({pattern:e,template:t,patternManifest:s,demo:a})=>{if(a?.type&&a.type==="data"){let{data:{props:o,slots:i,slotsOptionsComputed:l}}=a,m=this.getJsImport({patternId:e.id,templateId:t.id});if(!m)throw new Error(`Could not find import for pattern-template: ${e.id}-${t.id}`);let{type:n,name:p}=m.importInfo,u=[m],f=[],y=[];if(i){let d=Object.keys(i);(await Promise.all(d.map(async w=>{let T=i[w],D=await Promise.all(T.filter(g=>!(g.type!=="text"&&(!g.patternId||!g.templateId||g.type==="template-demo"&&!g.demoId))).map(async g=>{if(g.type==="text")return T.length===1&&w!=="children"?`\`${g.text}\``:g.text;let I=s.getPattern(g.patternId),b=I.templates.find(k=>k.id===g.templateId);if(g.type==="template-reference"){let{usage:k,imports:E}=await this.getUsageAndImports({pattern:I,template:b,patternManifest:s});return u.push(...E),k}if(g.type==="template-demo"){let{usage:k,imports:E}=await this.getUsageAndImports({pattern:I,template:b,demo:g.demo||this.patterns.demosById[g.demoId],patternManifest:s});return u.push(...E),k}throw new Error(`Unknown slot item: ${JSON.stringify(g)}`)}));return {slotName:w,slotItemsUsages:D}}))).forEach(({slotName:w,slotItemsUsages:T})=>{let D=l?.[w],{openTag:g,closeTag:I}=createSlotOptionsHtmlTags({slotOptionsComputed:D,classAttributeName:"className",stylesValueType:"object"});g&&(w==="children"?f.push(g):y.push({key:w,value:g})),T.forEach(b=>{w==="children"?f.push(b):y.push({key:w,value:b});}),I&&(w==="children"?f.push(I):y.push({key:w,value:I}));});}return {usage:await M({templateName:p,props:o,children:f.join(`
41
- `),extraProps:y}),imports:u}}if(a?.type&&a.type==="template"){let o=this.getJsImport({patternId:e.id,templateId:t.id,demoId:a.id});if(!o)throw new Error(`Could not find import for pattern-template-demo: ${e.id}-${t.id}-${a.id}`);let{type:i,name:l}=o.importInfo;return {usage:await M({templateName:l}),imports:[o]}}if(!a){let o=this.getJsImport({patternId:e.id,templateId:t.id});if(!o)throw new Error(`Could not find import for pattern-template: ${e.id}-${t.id}`);let{type:i,name:l}=o.importInfo;return {usage:l,imports:[o]}}throw new Error(`Unhandled demo type for ${e.id}-${t.id}: ${JSON.stringify(a)}`)},"getUsageAndImports");inferSpec=c(async({template:e,templatePath:t})=>{let s=await B({src:e.path,exportName:e.alias||"default",resolveFromDir:this.config.data});if(s!==!1){let a=Object.keys(s?.props?.properties||{}).length,o=Object.keys(s?.slots||{}).length;if(a===0&&o===0)return !1}return s},"inferSpec");watch=c(async e=>{super.watch(e),knapsackEvents.onPatternTemplateChanged(()=>{V();});},"watch");getTemplateMeta=c(async({pattern:e,template:t})=>{let s=[];if(t?.spec?.props){let a=JSON.parse(JSON.stringify(t.spec.props));t?.spec?.slots&&Object.entries(t.spec.slots).forEach(([i,l])=>{a.properties[i]={typeof:"function",tsType:"React.ReactNode",description:l.allowedPatternIds?`${l.description}. Only use: ${l.allowedPatternIds.join(", ")}`:l.description},a.required=a.required??[],l.isRequired&&a.required.push(i);});let o=await r.convertSchemaToTypeScriptDefs({schema:a,title:`${this.changeCase(e.id)}Props`,description:`[Knapsack Docs](http://localhost:3999/pattern/${e.id}/${t.id})`,patternId:e.id,templateId:t.id,postBanner:"import * as React from 'react';"});s.push({contents:o,encoding:"utf8",path:`${e.id}.${t.id}.spec.d.ts`}),s.push({contents:JSON.stringify(a,null," "),encoding:"utf8",path:`${e.id}.${t.id}.spec.json`});}return s},"getTemplateMeta");alterTemplateMetaFiles=c(async({files:e,metaDir:t})=>{let s=[],a=".spec.d.ts";return e.forEach(o=>{if(o.path.endsWith(a)){let{base:i}=parse(o.path),[l,m]=i.split("."),n=m===this.id,p=this.changeCase(`${l}Props`),u=this.changeCase(`${l}-${m}Props`);s.push(`export { ${n?p:`${p} as ${u}`} } from './${relative(t,o.path).replace(".d.ts","")}';`);}}),s.push(""),[...e,{contents:s.join(`
42
- `),encoding:"utf8",path:join(t,"react.d.ts")}]},"alterTemplateMetaFiles");getTemplateSuggestions=c(async({newPath:e})=>{let{data:t}=this.patterns.userConfig,{allTemplateDemos:s,allTemplates:a}=this.getMyTemplates(),o=[...s,...a].map(({path:n,alias:p})=>({path:n,alias:p||"default"})),i=[...new Set([e,...o.map(({path:n})=>n)])];return {suggestions:(await Promise.all(i.map(async n=>{if(!n)return [];try{let{exports:p,errorMsg:u}=await getJsExportNames({path:n,resolveFromDir:t,pkgPathAliases:this.pkgPathAliases});if(u)throw new Error(u);return p.filter(f=>f==="default"||isFirstLetterCapital(f)).map(f=>({alias:f,path:n}))}catch(p){return log.verbose(`Error getting import names for ${n}: ${p.message}`,null,this.logPrefix),[]}})).then(n=>n.flat())).filter(n=>!o.find(p=>p.alias===n.alias&&p.path===n.path))}},"getTemplateSuggestions")};
43
-
44
- export { Q as KnapsackReactRenderer };
45
- //# sourceMappingURL=index.mjs.map
881
+ ${this.assets.map((asset) => `<script src="${asset}"></script>`).join("\n")}
882
+ ${RendererWebpackBase.createHtmlTagsForAssetPaths({
883
+ assets: this.getWebpackAssetPaths(),
884
+ // we need the scripts to finish adding methods to the global knapsack object synchronously before the client-side code runs that is in the <script> tag below
885
+ scriptTagsAreAsync: false
886
+ })}
887
+ ${errorHtmlMsg}
888
+ `;
889
+ return {
890
+ ok: !errorHtmlMsg,
891
+ html: await formatCode2({
892
+ contents: html,
893
+ path: "x.html"
894
+ // doing this to set format language
895
+ }),
896
+ usage,
897
+ templateLanguage: this.language
898
+ };
899
+ }
900
+ render = /* @__PURE__ */ __name(async (opt) => {
901
+ if (opt.demo?.type === "template") {
902
+ const waits = [5, 10, 20, 50, 100, 1e3, 1e3];
903
+ let templateDemoPath;
904
+ let attempt = 0;
905
+ while (true) {
906
+ try {
907
+ const { absolutePath, exists } = await this.resolvePath(
908
+ opt.demo.templateInfo.path
909
+ );
910
+ if (!exists) {
911
+ throw new Error(
912
+ `Template demo file does not exist: ${absolutePath}`
913
+ );
914
+ }
915
+ templateDemoPath = absolutePath;
916
+ break;
917
+ } catch (e) {
918
+ const waitTime = waits[attempt];
919
+ if (!waitTime) {
920
+ throw new Error(e);
921
+ }
922
+ attempt += 1;
923
+ await sleep(waitTime);
924
+ }
925
+ }
926
+ const [templateFileContents, { usage, importMap }] = await Promise.all([
927
+ readFile2(templateDemoPath),
928
+ this.getUsageAndImports({
929
+ ...opt,
930
+ importMap: /* @__PURE__ */ new Map()
931
+ })
932
+ ]);
933
+ const demoApp = await getDemoAppUsage({
934
+ children: usage
935
+ });
936
+ const results = await this.prepClientRenderResults({
937
+ usage: templateFileContents,
938
+ demoApp,
939
+ renderOptions: opt,
940
+ importMap
941
+ });
942
+ return results;
943
+ }
944
+ if (opt.demo?.type === "data") {
945
+ const { usage, importMap } = await this.getUsageAndImports({
946
+ ...opt,
947
+ importMap: /* @__PURE__ */ new Map()
948
+ });
949
+ const importCode = RendererWebpackBase.createJsImportCodeBlock({
950
+ importMap
951
+ });
952
+ const [demoAppUsage, demoApp] = await Promise.all([
953
+ getDemoAppUsage({
954
+ children: usage,
955
+ imports: importCode,
956
+ format: true
957
+ }),
958
+ getDemoAppUsage({
959
+ children: usage
960
+ })
961
+ ]);
962
+ return this.prepClientRenderResults({
963
+ demoApp,
964
+ usage: demoAppUsage,
965
+ renderOptions: opt,
966
+ importMap
967
+ });
968
+ }
969
+ }, "render");
970
+ getUsageAndImports = /* @__PURE__ */ __name(async ({
971
+ patternId,
972
+ templateId,
973
+ demo,
974
+ state,
975
+ importMap
976
+ }) => {
977
+ if (!demo) {
978
+ throw new Error(
979
+ `No demo provided while rendering ${patternId} ${templateId}`
980
+ );
981
+ }
982
+ const pattern = state.patterns[patternId];
983
+ if (!pattern) {
984
+ throw new Error(`Could not find pattern: ${patternId}`);
985
+ }
986
+ if (demo.type === "data") {
987
+ const template = pattern.templates.find((t) => t.id === templateId);
988
+ if (!template) {
989
+ throw new Error(`Could not find template: ${templateId}`);
990
+ }
991
+ const {
992
+ data: { props, slots, slotsOptionsComputed }
993
+ } = demo;
994
+ const { name: templateName } = await this.addUniqueValueToImportMap({
995
+ importMap,
996
+ path: template.path,
997
+ alias: template.alias || "default"
998
+ });
999
+ const children = [];
1000
+ const extraProps = [];
1001
+ if (slots) {
1002
+ const slotNames = Object.keys(slots);
1003
+ const slotUsages = await Promise.all(
1004
+ slotNames.map(async (slotName) => {
1005
+ const slotItems = slots[slotName];
1006
+ const slotItemsUsages = await Promise.all(
1007
+ slotItems.filter((slotItem) => {
1008
+ if (!slotItem) return false;
1009
+ if (slotItem.type !== "text") {
1010
+ if (!slotItem.patternId) return false;
1011
+ if (!slotItem.templateId) return false;
1012
+ if (slotItem.type === "template-demo" && !slotItem.demoId) {
1013
+ return false;
1014
+ }
1015
+ }
1016
+ return true;
1017
+ }).map(async (slotItem) => {
1018
+ if (slotItem.type === "text") {
1019
+ if (slotItems.length === 1 && slotName !== "children") {
1020
+ return `\`${slotItem.text}\``;
1021
+ }
1022
+ return slotItem.text;
1023
+ }
1024
+ if (slotItem.type === "template-reference") {
1025
+ const slottedTemplate = state.patterns[slotItem.patternId]?.templates.find((t) => t.id === slotItem.templateId);
1026
+ if (!slottedTemplate) {
1027
+ throw new Error(
1028
+ `Could not find slotted template: ${slotItem.patternId} ${slotItem.templateId}`
1029
+ );
1030
+ }
1031
+ const templateRefImport = await this.addUniqueValueToImportMap({
1032
+ importMap,
1033
+ path: slottedTemplate.path,
1034
+ alias: slottedTemplate.alias || "default"
1035
+ });
1036
+ return templateRefImport.name;
1037
+ }
1038
+ if (slotItem.type === "template-demo") {
1039
+ const thisDemo = slotItem.demo;
1040
+ if (!thisDemo) {
1041
+ throw new Error(
1042
+ `Could not find slotted template demo ${JSON.stringify(
1043
+ slotItem
1044
+ )}`
1045
+ );
1046
+ }
1047
+ const { usage: usage2 } = await this.getUsageAndImports({
1048
+ patternId: thisDemo.patternId,
1049
+ templateId: thisDemo.templateId,
1050
+ demo: thisDemo,
1051
+ state,
1052
+ importMap
1053
+ });
1054
+ return usage2;
1055
+ }
1056
+ const _exhaustiveCheck2 = slotItem;
1057
+ throw new Error(
1058
+ `Unknown slot item: ${JSON.stringify(slotItem)}`
1059
+ );
1060
+ })
1061
+ );
1062
+ return {
1063
+ slotName,
1064
+ slotItemsUsages
1065
+ };
1066
+ })
1067
+ );
1068
+ slotUsages.forEach(({ slotName, slotItemsUsages }) => {
1069
+ const slotOptionsComputed = slotsOptionsComputed?.[slotName];
1070
+ const { openTag, closeTag } = createSlotOptionsHtmlTags({
1071
+ slotOptionsComputed,
1072
+ classAttributeName: "className",
1073
+ stylesValueType: "object"
1074
+ });
1075
+ if (openTag) {
1076
+ if (slotName === "children") {
1077
+ children.push(openTag);
1078
+ } else {
1079
+ extraProps.push({
1080
+ key: slotName,
1081
+ value: openTag
1082
+ });
1083
+ }
1084
+ }
1085
+ slotItemsUsages.forEach((usage2) => {
1086
+ if (slotName === "children") {
1087
+ children.push(usage2);
1088
+ } else {
1089
+ extraProps.push({
1090
+ key: slotName,
1091
+ value: usage2
1092
+ });
1093
+ }
1094
+ });
1095
+ if (closeTag) {
1096
+ if (slotName === "children") {
1097
+ children.push(closeTag);
1098
+ } else {
1099
+ extraProps.push({
1100
+ key: slotName,
1101
+ value: closeTag
1102
+ });
1103
+ }
1104
+ }
1105
+ });
1106
+ }
1107
+ const usage = await getUsage({
1108
+ templateName,
1109
+ props,
1110
+ children: children.join("\n"),
1111
+ extraProps
1112
+ });
1113
+ return {
1114
+ usage,
1115
+ importMap
1116
+ };
1117
+ }
1118
+ if (demo.type === "template") {
1119
+ const { templateInfo } = demo;
1120
+ const { name: templateName } = await this.addUniqueValueToImportMap({
1121
+ importMap,
1122
+ path: templateInfo.path,
1123
+ alias: templateInfo.alias || "default"
1124
+ });
1125
+ const usage = await getUsage({ templateName });
1126
+ return {
1127
+ usage,
1128
+ importMap
1129
+ };
1130
+ }
1131
+ const _exhaustiveCheck = demo;
1132
+ throw new Error(
1133
+ `Unhandled demo type for ${patternId}-${templateId}: ${JSON.stringify(
1134
+ demo
1135
+ )}`
1136
+ );
1137
+ }, "getUsageAndImports");
1138
+ inferSpec = /* @__PURE__ */ __name(async ({
1139
+ template,
1140
+ templatePath
1141
+ }) => {
1142
+ const spec = await getReactDocs({
1143
+ src: template.path,
1144
+ exportName: template.alias || "default",
1145
+ resolveFromDir: this.config.data
1146
+ });
1147
+ if (spec !== false) {
1148
+ const totalProps = Object.keys(spec?.props?.properties || {}).length;
1149
+ const totalSlots = Object.keys(spec?.slots || {}).length;
1150
+ if (totalProps === 0 && totalSlots === 0) {
1151
+ return false;
1152
+ }
1153
+ }
1154
+ return spec;
1155
+ }, "inferSpec");
1156
+ watch = /* @__PURE__ */ __name(async () => {
1157
+ super.watch();
1158
+ knapsackEvents.onPatternTemplateChanged(() => {
1159
+ clearInferSpecCache();
1160
+ });
1161
+ }, "watch");
1162
+ getTemplateMeta = /* @__PURE__ */ __name(async ({
1163
+ pattern,
1164
+ template
1165
+ }) => {
1166
+ const files = [];
1167
+ if (template?.spec?.props) {
1168
+ const schema = JSON.parse(JSON.stringify(template.spec.props));
1169
+ if (template?.spec?.slots) {
1170
+ Object.entries(template.spec.slots).forEach(([id, info]) => {
1171
+ schema.properties[id] = {
1172
+ typeof: "function",
1173
+ tsType: "React.ReactNode",
1174
+ description: info.allowedPatternIds ? `${info.description}. Only use: ${info.allowedPatternIds.join(
1175
+ ", "
1176
+ )}` : info.description
1177
+ };
1178
+ schema.required = schema.required ?? [];
1179
+ if (info.isRequired) schema.required.push(id);
1180
+ });
1181
+ }
1182
+ const typeDefs = await _KnapsackReactRenderer.convertSchemaToTypeScriptDefs({
1183
+ schema,
1184
+ title: `${this.changeCase(pattern.id)}Props`,
1185
+ // @todo pull in base url
1186
+ description: `[Knapsack Docs](http://localhost:3999/pattern/${pattern.id}/${template.id})`,
1187
+ patternId: pattern.id,
1188
+ templateId: template.id,
1189
+ postBanner: `import * as React from 'react';`
1190
+ });
1191
+ files.push({
1192
+ contents: typeDefs,
1193
+ encoding: "utf8",
1194
+ path: `${pattern.id}.${template.id}.spec.d.ts`
1195
+ });
1196
+ files.push({
1197
+ contents: JSON.stringify(schema, null, " "),
1198
+ encoding: "utf8",
1199
+ path: `${pattern.id}.${template.id}.spec.json`
1200
+ });
1201
+ }
1202
+ return files;
1203
+ }, "getTemplateMeta");
1204
+ alterTemplateMetaFiles = /* @__PURE__ */ __name(async ({
1205
+ files,
1206
+ metaDir
1207
+ }) => {
1208
+ const imports = [];
1209
+ const ext = ".spec.d.ts";
1210
+ files.forEach((file) => {
1211
+ if (file.path.endsWith(ext)) {
1212
+ const { base } = parse(file.path);
1213
+ const [patternId, templateId] = base.split(".");
1214
+ const isFirst = templateId === this.id;
1215
+ const exportName = this.changeCase(`${patternId}Props`);
1216
+ const exportNameWithTemplateId = this.changeCase(
1217
+ `${patternId}-${templateId}Props`
1218
+ );
1219
+ imports.push(
1220
+ `export { ${isFirst ? exportName : `${exportName} as ${exportNameWithTemplateId}`} } from './${relative(metaDir, file.path).replace(".d.ts", "")}';`
1221
+ );
1222
+ }
1223
+ });
1224
+ imports.push("");
1225
+ return [
1226
+ ...files,
1227
+ {
1228
+ contents: imports.join("\n"),
1229
+ encoding: "utf8",
1230
+ path: join(metaDir, "react.d.ts")
1231
+ }
1232
+ ];
1233
+ }, "alterTemplateMetaFiles");
1234
+ getTemplateSuggestions = /* @__PURE__ */ __name(async ({
1235
+ newPath,
1236
+ state
1237
+ }) => {
1238
+ const usedSuggestions = Object.values(state.patterns).reduce(
1239
+ (acc, { templateDemos, templates }) => {
1240
+ templates.forEach(({ path: path3, alias, templateLanguageId }) => {
1241
+ if (templateLanguageId !== this.id) return;
1242
+ acc.push({ path: path3, alias });
1243
+ });
1244
+ templateDemos.forEach(
1245
+ ({ templateInfo: { path: path3, alias }, templateLanguageId }) => {
1246
+ if (templateLanguageId !== this.id) return;
1247
+ acc.push({ path: path3, alias });
1248
+ }
1249
+ );
1250
+ return acc;
1251
+ },
1252
+ []
1253
+ );
1254
+ const codeSrcs = new Set(this.getCodeSrcs());
1255
+ codeSrcs.delete(this.demoWrapperPath);
1256
+ codeSrcs.delete(errorCatcherPath);
1257
+ const allPaths = [
1258
+ .../* @__PURE__ */ new Set([
1259
+ newPath,
1260
+ ...Object.keys(this.pkgPathAliases || {}),
1261
+ ...codeSrcs
1262
+ ])
1263
+ ];
1264
+ const allSuggestions = await Promise.all(
1265
+ allPaths.map(async (path3) => {
1266
+ if (!path3) return [];
1267
+ try {
1268
+ const { exports, errorMsg } = await getJsExportNames2({
1269
+ path: path3,
1270
+ resolveFromDir: this.dataDir,
1271
+ pkgPathAliases: this.pkgPathAliases
1272
+ });
1273
+ if (errorMsg) {
1274
+ throw new Error(errorMsg);
1275
+ }
1276
+ return exports.filter((e) => e === "default" || isFirstLetterCapital(e)).map((name) => ({
1277
+ alias: name,
1278
+ path: path3
1279
+ }));
1280
+ } catch (e) {
1281
+ log2.verbose(
1282
+ `Error getting import names for ${path3}: ${e.message}`,
1283
+ null,
1284
+ this.logPrefix
1285
+ );
1286
+ return [];
1287
+ }
1288
+ })
1289
+ ).then((results) => {
1290
+ return results.flat();
1291
+ });
1292
+ const suggestions = allSuggestions.filter((s) => {
1293
+ return !usedSuggestions.find(
1294
+ (us) => us.alias === s.alias && us.path === s.path
1295
+ );
1296
+ });
1297
+ return {
1298
+ suggestions
1299
+ };
1300
+ }, "getTemplateSuggestions");
1301
+ };
1302
+ export {
1303
+ KnapsackReactRenderer
1304
+ };
46
1305
  //# sourceMappingURL=index.mjs.map