@knapsack/renderer-react 4.70.0--canary.3797.b249674.0 → 4.70.0--canary.4821.e250df4.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/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