@knapsack/renderer-web-components 5.0.0--canary.6593.4738696.0 → 5.0.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.
@@ -1,19 +1,7 @@
1
1
  "use strict";
2
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
- if (kind === "m") throw new TypeError("Private method is not writable");
4
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
- };
8
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
- };
13
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
14
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
15
4
  };
16
- var _KnapsackWebComponentRenderer_instances, _KnapsackWebComponentRenderer_customElementManifestPath, _KnapsackWebComponentRenderer_analyzeResults, _KnapsackWebComponentRenderer_analyzeManifest;
17
5
  Object.defineProperty(exports, "__esModule", { value: true });
18
6
  exports.KnapsackWebComponentRenderer = void 0;
19
7
  const chokidar_1 = __importDefault(require("chokidar"));
@@ -23,342 +11,374 @@ const types_1 = require("@knapsack/types");
23
11
  const path_1 = require("path");
24
12
  const file_utils_1 = require("@knapsack/file-utils");
25
13
  const cheerio_1 = require("cheerio");
14
+ const zod_1 = require("zod");
26
15
  const utils_1 = require("./utils");
27
16
  const pkg = JSON.parse((0, file_utils_1.readFileSync)((0, path_1.join)(__dirname, '../package.json')));
17
+ const OptionSchema = zod_1.z
18
+ .strictObject({
19
+ /**
20
+ * Path to a custom-elements.json file.
21
+ * https://github.com/runem/web-component-analyzer
22
+ */
23
+ customElementManifestSchemaPath: zod_1.z.string().optional(),
24
+ /**
25
+ * Function to wrap demo content.
26
+ */
27
+ demoWrapper: zod_1.z
28
+ .custom()
29
+ .optional(),
30
+ })
31
+ .meta({
32
+ id: types_1.rendererIds['web-components'],
33
+ title: 'Web Components',
34
+ });
28
35
  class KnapsackWebComponentRenderer extends renderers_1.RendererBase {
29
- constructor({ customElementManifestSchemaPath, } = {}) {
36
+ #customElementManifestPath;
37
+ #analyzeResults = Promise.resolve([]);
38
+ #demoWrapper;
39
+ constructor(options = {}) {
40
+ const { error: optionsError } = OptionSchema.safeParse(options);
41
+ const { customElementManifestSchemaPath, demoWrapper } = options;
30
42
  super({
31
43
  id: types_1.rendererIds['web-components'],
32
44
  language: 'html',
33
45
  codeSrcsUserConfig: [],
34
46
  });
35
- _KnapsackWebComponentRenderer_instances.add(this);
36
- _KnapsackWebComponentRenderer_customElementManifestPath.set(this, void 0);
37
- _KnapsackWebComponentRenderer_analyzeResults.set(this, Promise.resolve([]));
38
- this.setConfig = (opt) => {
39
- super.setConfig(opt);
40
- if (__classPrivateFieldGet(this, _KnapsackWebComponentRenderer_customElementManifestPath, "f")) {
41
- const { absolutePath, exists } = this.resolvePathSync({
42
- path: __classPrivateFieldGet(this, _KnapsackWebComponentRenderer_customElementManifestPath, "f"),
43
- resolveFromDir: this.userConfigDir,
44
- });
45
- if (!exists) {
46
- throw new Error(`Cannot find custom element manifest schema at ${__classPrivateFieldGet(this, _KnapsackWebComponentRenderer_customElementManifestPath, "f")}`);
47
- }
48
- __classPrivateFieldSet(this, _KnapsackWebComponentRenderer_customElementManifestPath, absolutePath, "f");
49
- __classPrivateFieldSet(this, _KnapsackWebComponentRenderer_analyzeResults, __classPrivateFieldGet(this, _KnapsackWebComponentRenderer_instances, "m", _KnapsackWebComponentRenderer_analyzeManifest).call(this), "f");
47
+ if (optionsError) {
48
+ this.log.error(`"KnapsackWebComponentRenderer" constructor has invalid options, please fix in "knapsack.config.cjs":`, zod_1.z.prettifyError(optionsError));
49
+ process.exit(1);
50
+ return;
51
+ }
52
+ this.#customElementManifestPath = customElementManifestSchemaPath;
53
+ this.#demoWrapper = demoWrapper;
54
+ }
55
+ setConfig = (opt) => {
56
+ super.setConfig(opt);
57
+ if (this.#customElementManifestPath) {
58
+ const { absolutePath, exists } = this.resolvePathSync({
59
+ path: this.#customElementManifestPath,
60
+ resolveFromDir: this.userConfigDir,
61
+ });
62
+ if (!exists) {
63
+ throw new Error(`Cannot find custom element manifest schema at ${this.#customElementManifestPath}`);
50
64
  }
51
- };
52
- this.render = async (opt) => {
53
- const usage = await this.getUsage(opt);
65
+ this.#customElementManifestPath = absolutePath;
66
+ this.#analyzeResults = this.#analyzeManifest();
67
+ }
68
+ };
69
+ async #analyzeManifest() {
70
+ if (!this.#customElementManifestPath)
71
+ return;
72
+ try {
73
+ const { analyzeManifest } = await import('./analyze/index.mjs');
74
+ const customElementManifest = await (0, file_utils_1.readJSON)(this.#customElementManifestPath);
75
+ return analyzeManifest({ customElementManifest });
76
+ }
77
+ catch (e) {
78
+ throw new Error(`Errors in custom element manifest from "${this.#customElementManifestPath}".\n${e.message}`);
79
+ }
80
+ }
81
+ render = async (opt) => {
82
+ const usage = await this.getUsage(opt);
83
+ if (this.#demoWrapper) {
84
+ const contents = await this.#demoWrapper({ content: usage });
54
85
  return {
55
86
  ok: true,
56
- html: await (0, file_utils_1.formatCode)({
57
- contents: usage,
58
- path: 'x.html',
59
- }),
87
+ // what is actually rendered in the iframe - which includes the demo wrapper (no need to format it)
88
+ html: contents,
89
+ // shows in code block - so we format it w/o demo wrapper
90
+ usage: await (0, file_utils_1.formatCode)({ contents, path: 'x.html' }),
60
91
  };
92
+ }
93
+ return {
94
+ ok: true,
95
+ // both renderer in iframe AND in code block since `usage` is not returned
96
+ html: await (0, file_utils_1.formatCode)({ contents: usage, path: 'x.html' }),
61
97
  };
62
- this.getUsage = async ({ demo, state }) => {
63
- if (!demo) {
64
- throw new Error(`No demo provide when rendering `);
98
+ };
99
+ getUsage = async ({ demo, state }) => {
100
+ if (!demo) {
101
+ throw new Error(`No demo provide when rendering `);
102
+ }
103
+ switch (demo.type) {
104
+ case 'template': {
105
+ const { templateInfo } = demo;
106
+ const { absolutePath, exists } = await this.resolvePath(templateInfo.path);
107
+ if (!exists) {
108
+ throw new Error(`Cannot find template demo at ${absolutePath}`);
109
+ }
110
+ return (0, file_utils_1.readFile)(absolutePath);
65
111
  }
66
- switch (demo.type) {
67
- case 'template': {
68
- const { templateInfo } = demo;
69
- const { absolutePath, exists } = await this.resolvePath(templateInfo.path);
70
- if (!exists) {
71
- throw new Error(`Cannot find template demo at ${absolutePath}`);
72
- }
73
- return (0, file_utils_1.readFile)(absolutePath);
112
+ case 'data-w-template-info':
113
+ case 'data': {
114
+ const { elementName } = this.normalizeDemo({ demo, state });
115
+ const { data: { props, slots, slotsOptionsComputed }, } = demo;
116
+ if (!slots) {
117
+ return (0, utils_1.getUsage)({
118
+ templateName: elementName,
119
+ props,
120
+ });
74
121
  }
75
- case 'data-w-template-info':
76
- case 'data': {
77
- const { elementName } = this.normalizeDemo({ demo, state });
78
- const { data: { props, slots, slotsOptionsComputed }, } = demo;
79
- if (!slots) {
80
- return (0, utils_1.getUsage)({
81
- templateName: elementName,
82
- props,
83
- });
84
- }
85
- const children = [];
86
- await Promise.all(Object.keys(slots).map(async (slotName) => {
87
- const slottedTemplates = slots[slotName];
88
- await Promise.all(slottedTemplates.map(async (slottedTemplate) => {
89
- if (slottedTemplate.type === 'text') {
90
- return {
91
- slottedTemplate,
92
- content: slottedTemplate.text,
93
- };
94
- }
95
- if (slottedTemplate.type === 'template-reference') {
96
- throw new Error(`Cannot handle slotted template references in ${JSON.stringify({
97
- demoId: demo.id,
98
- slottedTemplate,
99
- })}`);
100
- }
101
- if (!slottedTemplate.demoId) {
102
- return {
103
- slottedTemplate,
104
- content: '',
105
- };
106
- }
107
- const usage = await this.getUsage({
108
- demo: slottedTemplate.demo,
109
- state,
110
- });
122
+ const children = [];
123
+ await Promise.all(Object.keys(slots).map(async (slotName) => {
124
+ const slottedTemplates = slots[slotName];
125
+ await Promise.all(slottedTemplates.map(async (slottedTemplate) => {
126
+ if (slottedTemplate.type === 'text') {
111
127
  return {
112
128
  slottedTemplate,
113
- content: usage,
129
+ content: slottedTemplate.text,
114
130
  };
115
- })).then((usages) => {
116
- var _a;
117
- const slotOptionsComputed = slotsOptionsComputed === null || slotsOptionsComputed === void 0 ? void 0 : slotsOptionsComputed[slotName];
118
- const { openTag, closeTag } = (0, renderers_1.createSlotOptionsHtmlTags)({
119
- slotOptionsComputed,
120
- classAttributeName: 'class',
121
- stylesValueType: 'string',
122
- });
123
- const content = usages.map((usage) => usage.content).join('\n');
124
- if (slotName === 'default') {
125
- children.push(openTag, content, closeTag);
126
- return;
127
- }
128
- if (usages.length === 1 &&
129
- usages.every((usage) => usage.slottedTemplate.type === 'text')) {
130
- // this may be a single slot item with HTML in it
131
- const text = ((_a = usages[0].content) === null || _a === void 0 ? void 0 : _a.trim()) || '';
132
- if (text.startsWith('<') && text.endsWith('>')) {
133
- // looks enough like HTML given the starting and ending angle brackets
134
- // say it was `<p>hi</p>` - we want `<p slot="my-slot">hi</p>` instead of `<div slot="my-slot"><p>hi</p></div>`
135
- const $ = (0, cheerio_1.load)(text);
136
- const firstElem = $('body :first');
137
- if (firstElem) {
138
- firstElem.attr('slot', slotName);
139
- children.push(openTag, $('body').html(), closeTag);
140
- return;
141
- }
131
+ }
132
+ if (slottedTemplate.type === 'template-reference') {
133
+ throw new Error(`Cannot handle slotted template references in ${JSON.stringify({
134
+ demoId: demo.id,
135
+ slottedTemplate,
136
+ })}`);
137
+ }
138
+ if (!slottedTemplate.demoId) {
139
+ return {
140
+ slottedTemplate,
141
+ content: '',
142
+ };
143
+ }
144
+ const usage = await this.getUsage({
145
+ demo: slottedTemplate.demo,
146
+ state,
147
+ });
148
+ return {
149
+ slottedTemplate,
150
+ content: usage,
151
+ };
152
+ })).then((usages) => {
153
+ const slotOptionsComputed = slotsOptionsComputed?.[slotName];
154
+ const { openTag, closeTag } = (0, renderers_1.createSlotOptionsHtmlTags)({
155
+ slotOptionsComputed,
156
+ classAttributeName: 'class',
157
+ stylesValueType: 'string',
158
+ });
159
+ const content = usages.map((usage) => usage.content).join('\n');
160
+ if (slotName === 'default') {
161
+ children.push(openTag, content, closeTag);
162
+ return;
163
+ }
164
+ if (usages.length === 1 &&
165
+ usages.every((usage) => usage.slottedTemplate.type === 'text')) {
166
+ // this may be a single slot item with HTML in it
167
+ const text = usages[0].content?.trim() || '';
168
+ if (text.startsWith('<') && text.endsWith('>')) {
169
+ // looks enough like HTML given the starting and ending angle brackets
170
+ // say it was `<p>hi</p>` - we want `<p slot="my-slot">hi</p>` instead of `<div slot="my-slot"><p>hi</p></div>`
171
+ const $ = (0, cheerio_1.load)(text);
172
+ const firstElem = $('body :first');
173
+ if (firstElem) {
174
+ firstElem.attr('slot', slotName);
175
+ children.push(openTag, $('body').html(), closeTag);
176
+ return;
142
177
  }
143
178
  }
144
- children.push(`<div slot="${slotName}">`, openTag, content, closeTag, `</div>`);
145
- });
146
- }));
147
- const usage = await (0, utils_1.getUsage)({
148
- templateName: elementName,
149
- props,
150
- children: children.filter(Boolean).join('\n'),
179
+ }
180
+ children.push(`<div slot="${slotName}">`, openTag, content, closeTag, `</div>`);
151
181
  });
152
- return usage;
153
- }
154
- default: {
155
- const _exhaustiveCheck = demo;
156
- throw new Error(`Must pass in a known demo.type, received ${JSON.stringify(demo)}`);
157
- }
158
- }
159
- };
160
- this.inspect = async ({ elementName }) => {
161
- const results = await __classPrivateFieldGet(this, _KnapsackWebComponentRenderer_analyzeResults, "f");
162
- if (!results.length) {
163
- return {
164
- type: 'renderer.noInspectSupported',
165
- };
182
+ }));
183
+ const usage = await (0, utils_1.getUsage)({
184
+ templateName: elementName,
185
+ props,
186
+ children: children.filter(Boolean).join('\n'),
187
+ });
188
+ return usage;
166
189
  }
167
- const result = results.find((r) => r.tagName === elementName);
168
- if (!result) {
169
- return {
170
- type: 'noSpecInferred',
171
- };
190
+ default: {
191
+ const _exhaustiveCheck = demo;
192
+ throw new Error(`Must pass in a known demo.type, received ${JSON.stringify(demo)}`);
172
193
  }
173
- return { type: 'success', spec: result.spec };
174
- };
175
- this.getDiscovery = async () => {
176
- const results = await __classPrivateFieldGet(this, _KnapsackWebComponentRenderer_analyzeResults, "f");
194
+ }
195
+ };
196
+ inspect = async ({ elementName }) => {
197
+ const results = await this.#analyzeResults;
198
+ if (!results.length) {
177
199
  return {
178
- rendererId: this.id,
179
- meta: this.getMeta(),
180
- codeSrcsByPath: Object.fromEntries(this.codeSrcs.entries()),
181
- templates: results.map(({ tagName }) => (0, types_1.addIdToTemplateInfo)({
182
- rendererId: this.id,
183
- elementName: tagName,
184
- })),
200
+ type: 'renderer.noInspectSupported',
185
201
  };
202
+ }
203
+ const result = results.find((r) => r.tagName === elementName);
204
+ if (!result) {
205
+ return {
206
+ type: 'noSpecInferred',
207
+ };
208
+ }
209
+ return { type: 'success', spec: result.spec };
210
+ };
211
+ getDiscovery = async () => {
212
+ const results = await this.#analyzeResults;
213
+ return {
214
+ rendererId: this.id,
215
+ meta: this.getMeta(),
216
+ codeSrcsByPath: Object.fromEntries(this.codeSrcs.entries()),
217
+ templates: results.map(({ tagName }) => (0, types_1.addIdToTemplateInfo)({
218
+ rendererId: this.id,
219
+ elementName: tagName,
220
+ })),
186
221
  };
187
- this.getTemplateSuggestions = async ({ state, }) => {
188
- const { templates } = await this.getDiscovery();
189
- if (templates.length === 0)
190
- return { suggestions: [] };
191
- const tagNames = templates.map(({ elementName }) => elementName);
192
- const usedNames = Object.values(state.patterns).flatMap((p) => p.templates
193
- .filter((t) => t.templateLanguageId === this.id)
194
- .map((t) => t.alias));
195
- const suggestions = [
196
- // Used names with connected: true
197
- ...usedNames.map((name) => ({
198
- alias: name,
199
- path: '',
200
- connected: true,
201
- })),
202
- // Unused names with connected: false
203
- ...tagNames
204
- .filter((name) => !usedNames.includes(name))
205
- .map((name) => ({
206
- alias: name,
207
- path: '',
208
- connected: false,
209
- })),
210
- ];
211
- return { suggestions };
212
- };
213
- this.watch = async () => {
214
- super.watch();
215
- if (!__classPrivateFieldGet(this, _KnapsackWebComponentRenderer_customElementManifestPath, "f"))
216
- return;
217
- const watcher = chokidar_1.default.watch(__classPrivateFieldGet(this, _KnapsackWebComponentRenderer_customElementManifestPath, "f"), {
218
- ignoreInitial: true,
219
- });
220
- watcher.on('change', () => {
221
- __classPrivateFieldSet(this, _KnapsackWebComponentRenderer_analyzeResults, __classPrivateFieldGet(this, _KnapsackWebComponentRenderer_instances, "m", _KnapsackWebComponentRenderer_analyzeManifest).call(this), "f");
222
- app_1.knapsackEvents.emitAppClientDataChanged();
223
- this.onChange();
224
- });
225
- app_1.knapsackEvents.onShutdown(() => watcher.close());
226
- };
227
- this.getMeta = () => ({
228
- id: this.id,
229
- title: 'Web Components',
230
- aliasUse: 'required',
231
- aliasTitle: 'Custom Element Name',
232
- aliasDescription: 'The custom element tag name (ex. my-card)',
233
- enableDataDemos: true,
234
- enableTemplateDemos: true,
235
- hasSlotsSupport: true,
236
- hasSlotOptionsSupport: true,
237
- version: pkg.version,
238
- hasInferSpecSupport: !!__classPrivateFieldGet(this, _KnapsackWebComponentRenderer_customElementManifestPath, "f"),
239
- hasTemplateSuggestionsSupport: !!__classPrivateFieldGet(this, _KnapsackWebComponentRenderer_customElementManifestPath, "f"),
240
- prototypingTemplate: {
222
+ };
223
+ getTemplateSuggestions = async ({ state, }) => {
224
+ const { templates } = await this.getDiscovery();
225
+ if (templates.length === 0)
226
+ return { suggestions: [] };
227
+ const tagNames = templates.map(({ elementName }) => elementName);
228
+ const usedNames = Object.values(state.patterns).flatMap((p) => p.templates
229
+ .filter((t) => t.templateLanguageId === this.id)
230
+ .map((t) => t.alias));
231
+ const suggestions = [
232
+ // Used names with connected: true
233
+ ...usedNames.map((name) => ({
234
+ alias: name,
241
235
  path: '',
242
- alias: 'div',
243
- spec: {
244
- isInferred: false,
245
- props: {
246
- type: 'object',
247
- properties: {},
248
- },
249
- slots: {
250
- default: { title: 'Content' },
251
- },
236
+ connected: true,
237
+ })),
238
+ // Unused names with connected: false
239
+ ...tagNames
240
+ .filter((name) => !usedNames.includes(name))
241
+ .map((name) => ({
242
+ alias: name,
243
+ path: '',
244
+ connected: false,
245
+ })),
246
+ ];
247
+ return { suggestions };
248
+ };
249
+ watch = async () => {
250
+ super.watch();
251
+ if (!this.#customElementManifestPath)
252
+ return;
253
+ const watcher = chokidar_1.default.watch(this.#customElementManifestPath, {
254
+ ignoreInitial: true,
255
+ });
256
+ watcher.on('change', () => {
257
+ this.#analyzeResults = this.#analyzeManifest();
258
+ app_1.knapsackEvents.emitAppClientDataChanged();
259
+ this.onChange();
260
+ });
261
+ app_1.knapsackEvents.onShutdown(() => watcher.close());
262
+ };
263
+ getMeta = () => ({
264
+ id: this.id,
265
+ title: 'Web Components',
266
+ aliasUse: 'required',
267
+ aliasTitle: 'Custom Element Name',
268
+ aliasDescription: 'The custom element tag name (ex. my-card)',
269
+ enableDataDemos: true,
270
+ enableTemplateDemos: true,
271
+ hasSlotsSupport: true,
272
+ hasSlotOptionsSupport: true,
273
+ version: pkg.version,
274
+ hasInferSpecSupport: !!this.#customElementManifestPath,
275
+ hasTemplateSuggestionsSupport: !!this.#customElementManifestPath,
276
+ prototypingTemplate: {
277
+ path: '',
278
+ alias: 'div',
279
+ spec: {
280
+ isInferred: false,
281
+ props: {
282
+ type: 'object',
283
+ properties: {},
284
+ },
285
+ slots: {
286
+ default: { title: 'Content' },
252
287
  },
253
288
  },
254
- });
255
- this.getTemplateMeta = async ({ pattern, template, }) => {
256
- var _a, _b, _c;
257
- const files = [];
258
- const htmlCustomData = {
259
- version: 1.1,
260
- tags: [],
261
- };
262
- if ((0, types_1.isSpecNotInferred)(template.spec)) {
263
- const { spec } = template;
264
- const typeDefs = await KnapsackWebComponentRenderer.convertSchemaToTypeScriptDefs({
265
- schema: template.spec.props,
266
- title: pattern.id,
267
- patternId: pattern.id,
268
- templateId: template.id,
269
- });
270
- const attributes = [];
271
- Object.entries(((_a = spec.props) === null || _a === void 0 ? void 0 : _a.properties) || {}).forEach(([name, meta]) => {
272
- var _a, _b, _c;
273
- const descriptions = [];
274
- const attr = {
275
- name,
276
- };
277
- const isRequired = (_c = (_b = (_a = spec.props) === null || _a === void 0 ? void 0 : _a.required) === null || _b === void 0 ? void 0 : _b.includes(name)) !== null && _c !== void 0 ? _c : false;
278
- if (isRequired) {
279
- descriptions.push('(required)');
280
- }
281
- if ((0, types_1.isOptionsProp)(meta)) {
282
- attr.values = meta.enum.map((option) => ({
283
- name: String(option),
284
- }));
285
- }
286
- else if ((0, types_1.isBooleanProp)(meta)) {
287
- descriptions.push('boolean');
288
- }
289
- if (meta.description)
290
- descriptions.push(meta.description);
291
- attr.description = descriptions.join(' ');
292
- attributes.push(attr);
293
- });
294
- htmlCustomData.tags.push({
295
- name: template.alias,
296
- description: (_b = pattern.description) !== null && _b !== void 0 ? _b : '',
297
- references: [
298
- {
299
- name: 'Knapsack Docs',
300
- // @todo pull in base url
301
- url: `http://localhost:3999/pattern/${pattern.id}/${template.id}`,
302
- },
303
- ],
304
- attributes,
305
- });
306
- files.push({
307
- contents: JSON.stringify(htmlCustomData, null, ' '),
308
- encoding: 'utf8',
309
- path: `${pattern.id}.${template.id}.html-data.json`,
310
- });
311
- files.push({
312
- contents: typeDefs,
313
- encoding: 'utf8',
314
- path: `${pattern.id}.${template.id}.spec.d.ts`,
315
- });
316
- if (Object.keys(((_c = template.spec.props) === null || _c === void 0 ? void 0 : _c.properties) || {}).length > 0) {
317
- files.push({
318
- contents: JSON.stringify(template.spec.props, null, ' '),
319
- encoding: 'utf8',
320
- path: `${pattern.id}.${template.id}.spec.json`,
321
- });
322
- }
323
- }
324
- return files;
289
+ },
290
+ });
291
+ getTemplateMeta = async ({ pattern, template, }) => {
292
+ const files = [];
293
+ const htmlCustomData = {
294
+ version: 1.1,
295
+ tags: [],
325
296
  };
326
- this.alterTemplateMetaFiles = async ({ files, }) => {
327
- const newFiles = [];
328
- const htmlCustomData = {
329
- version: 1.1,
330
- tags: [],
331
- };
332
- files.forEach((file) => {
333
- if (!file.path.endsWith('html-data.json')) {
334
- newFiles.push(file);
297
+ if ((0, types_1.isSpecNotInferred)(template.spec)) {
298
+ const { spec } = template;
299
+ const typeDefs = await KnapsackWebComponentRenderer.convertSchemaToTypeScriptDefs({
300
+ schema: template.spec.props,
301
+ title: pattern.id,
302
+ patternId: pattern.id,
303
+ templateId: template.id,
304
+ });
305
+ const attributes = [];
306
+ Object.entries(spec.props?.properties || {}).forEach(([name, meta]) => {
307
+ const descriptions = [];
308
+ const attr = {
309
+ name,
310
+ };
311
+ const isRequired = spec.props?.required?.includes(name) ?? false;
312
+ if (isRequired) {
313
+ descriptions.push('(required)');
335
314
  }
336
- else {
337
- const data = JSON.parse(file.contents);
338
- data.tags.forEach((tag) => htmlCustomData.tags.push(tag));
315
+ if ((0, types_1.isOptionsProp)(meta)) {
316
+ attr.values = meta.enum.map((option) => ({
317
+ name: String(option),
318
+ }));
319
+ }
320
+ else if ((0, types_1.isBooleanProp)(meta)) {
321
+ descriptions.push('boolean');
339
322
  }
323
+ if (meta.description)
324
+ descriptions.push(meta.description);
325
+ attr.description = descriptions.join(' ');
326
+ attributes.push(attr);
340
327
  });
341
- newFiles.push({
328
+ htmlCustomData.tags.push({
329
+ name: template.alias,
330
+ description: pattern.description ?? '',
331
+ references: [
332
+ {
333
+ name: 'Knapsack Docs',
334
+ // @todo pull in base url
335
+ url: `http://localhost:3999/pattern/${pattern.id}/${template.id}`,
336
+ },
337
+ ],
338
+ attributes,
339
+ });
340
+ files.push({
342
341
  contents: JSON.stringify(htmlCustomData, null, ' '),
343
342
  encoding: 'utf8',
344
- path: `knapsack.html-data.json`,
343
+ path: `${pattern.id}.${template.id}.html-data.json`,
344
+ });
345
+ files.push({
346
+ contents: typeDefs,
347
+ encoding: 'utf8',
348
+ path: `${pattern.id}.${template.id}.spec.d.ts`,
345
349
  });
346
- return newFiles;
350
+ if (Object.keys(template.spec.props?.properties || {}).length > 0) {
351
+ files.push({
352
+ contents: JSON.stringify(template.spec.props, null, ' '),
353
+ encoding: 'utf8',
354
+ path: `${pattern.id}.${template.id}.spec.json`,
355
+ });
356
+ }
357
+ }
358
+ return files;
359
+ };
360
+ alterTemplateMetaFiles = async ({ files, }) => {
361
+ const newFiles = [];
362
+ const htmlCustomData = {
363
+ version: 1.1,
364
+ tags: [],
347
365
  };
348
- __classPrivateFieldSet(this, _KnapsackWebComponentRenderer_customElementManifestPath, customElementManifestSchemaPath, "f");
349
- }
366
+ files.forEach((file) => {
367
+ if (!file.path.endsWith('html-data.json')) {
368
+ newFiles.push(file);
369
+ }
370
+ else {
371
+ const data = JSON.parse(file.contents);
372
+ data.tags.forEach((tag) => htmlCustomData.tags.push(tag));
373
+ }
374
+ });
375
+ newFiles.push({
376
+ contents: JSON.stringify(htmlCustomData, null, ' '),
377
+ encoding: 'utf8',
378
+ path: `knapsack.html-data.json`,
379
+ });
380
+ return newFiles;
381
+ };
350
382
  }
351
383
  exports.KnapsackWebComponentRenderer = KnapsackWebComponentRenderer;
352
- _KnapsackWebComponentRenderer_customElementManifestPath = new WeakMap(), _KnapsackWebComponentRenderer_analyzeResults = new WeakMap(), _KnapsackWebComponentRenderer_instances = new WeakSet(), _KnapsackWebComponentRenderer_analyzeManifest = async function _KnapsackWebComponentRenderer_analyzeManifest() {
353
- if (!__classPrivateFieldGet(this, _KnapsackWebComponentRenderer_customElementManifestPath, "f"))
354
- return;
355
- try {
356
- const { analyzeManifest } = await import('./analyze/index.mjs');
357
- const customElementManifest = await (0, file_utils_1.readJSON)(__classPrivateFieldGet(this, _KnapsackWebComponentRenderer_customElementManifestPath, "f"));
358
- return analyzeManifest({ customElementManifest });
359
- }
360
- catch (e) {
361
- throw new Error(`Errors in custom element manifest from "${__classPrivateFieldGet(this, _KnapsackWebComponentRenderer_customElementManifestPath, "f")}".\n${e.message}`);
362
- }
363
- };
364
384
  //# sourceMappingURL=renderer-web-components.js.map