gesso-vite-plugin 0.6.30 → 0.8.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/CHANGELOG.md +28 -0
- package/dist/catalog-CbeOrdxD.d.ts +305 -0
- package/dist/contracts-Dwn5pg-0.js +1299 -0
- package/dist/contracts-Dwn5pg-0.js.map +1 -0
- package/dist/gesso-channels.mjs +322 -24
- package/dist/gesso-channels.mjs.map +1 -1
- package/dist/index.d.ts +42 -114
- package/dist/index.js +317 -710
- package/dist/index.js.map +1 -1
- package/dist/library.d.ts +56 -0
- package/dist/library.js +56 -0
- package/dist/library.js.map +1 -0
- package/package.json +5 -1
package/dist/gesso-channels.mjs
CHANGED
|
@@ -52,6 +52,8 @@ function importPath(fromDir, file) {
|
|
|
52
52
|
var ContractReader = class {
|
|
53
53
|
api = null;
|
|
54
54
|
changed = /* @__PURE__ */ new Set();
|
|
55
|
+
created = /* @__PURE__ */ new Set();
|
|
56
|
+
deleted = /* @__PURE__ */ new Set();
|
|
55
57
|
/** Each contract's tsconfig, found once. */
|
|
56
58
|
configs = /* @__PURE__ */ new Map();
|
|
57
59
|
/**
|
|
@@ -66,39 +68,69 @@ var ContractReader = class {
|
|
|
66
68
|
this.cwd = cwd;
|
|
67
69
|
this.fs = fs;
|
|
68
70
|
}
|
|
69
|
-
/**
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
/**
|
|
72
|
+
* A file changed on disk since the last read. A new or deleted one is
|
|
73
|
+
* said so, because a program's list of files only changes for those:
|
|
74
|
+
* a component in a new file is otherwise not in the catalog.
|
|
75
|
+
*/
|
|
76
|
+
invalidate(file, event = "update") {
|
|
77
|
+
(event === "create" ? this.created : event === "delete" ? this.deleted : this.changed).add(file);
|
|
72
78
|
}
|
|
73
|
-
/**
|
|
74
|
-
|
|
79
|
+
/**
|
|
80
|
+
* A snapshot of the projects, with what changed since the last one.
|
|
81
|
+
*
|
|
82
|
+
* The checker keeps every project it has opened, and asked to update
|
|
83
|
+
* one whose tsconfig has since been deleted it refuses the whole
|
|
84
|
+
* update ("project not found for update"). That was a dev server gone
|
|
85
|
+
* with it: a project's tsconfig removed while the server ran threw out
|
|
86
|
+
* of the catalog's read and took the process down. A refused update is
|
|
87
|
+
* a checker started afresh, which reads the disk as it now is and
|
|
88
|
+
* opens only what is asked of it again.
|
|
89
|
+
*/
|
|
90
|
+
snapshot(request) {
|
|
75
91
|
const api = this.api ??= new this.ts.API({
|
|
76
92
|
cwd: this.cwd,
|
|
77
93
|
...this.fs === void 0 ? {} : { fs: this.fs }
|
|
78
94
|
});
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (config === void 0) {
|
|
84
|
-
config = api.updateSnapshot({ openFiles: [file] }).getDefaultProjectForFile(file)?.configFileName;
|
|
85
|
-
snapshot = api.updateSnapshot({
|
|
86
|
-
...config === void 0 ? {} : { openProjects: [config] },
|
|
87
|
-
closeFiles: [file]
|
|
95
|
+
try {
|
|
96
|
+
return api.updateSnapshot({
|
|
97
|
+
...request,
|
|
98
|
+
fileChanges: this.takeChanges()
|
|
88
99
|
});
|
|
89
|
-
|
|
100
|
+
} catch {
|
|
101
|
+
this.close();
|
|
102
|
+
this.configs.clear();
|
|
103
|
+
const fresh = this.api = new this.ts.API({
|
|
104
|
+
cwd: this.cwd,
|
|
105
|
+
...this.fs === void 0 ? {} : { fs: this.fs }
|
|
106
|
+
});
|
|
107
|
+
const { fileChanges: _changes, ...rest } = request;
|
|
108
|
+
return fresh.updateSnapshot(rest);
|
|
90
109
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
110
|
+
}
|
|
111
|
+
/** What changed since the last snapshot, emptied for the next. */
|
|
112
|
+
takeChanges() {
|
|
113
|
+
const changes = {
|
|
114
|
+
changed: [...this.changed],
|
|
115
|
+
created: [...this.created],
|
|
116
|
+
deleted: [...this.deleted]
|
|
117
|
+
};
|
|
118
|
+
this.changed.clear();
|
|
119
|
+
this.created.clear();
|
|
120
|
+
this.deleted.clear();
|
|
121
|
+
return changes;
|
|
122
|
+
}
|
|
123
|
+
/** Every channel `file` exports, described. */
|
|
124
|
+
read(file) {
|
|
125
|
+
const opened = this.open(file);
|
|
126
|
+
if (typeof opened === "string") return {
|
|
94
127
|
channels: /* @__PURE__ */ new Map(),
|
|
95
|
-
warnings: [
|
|
128
|
+
warnings: [opened]
|
|
96
129
|
};
|
|
97
|
-
const checker =
|
|
98
|
-
const module = checker.getSymbolAtLocation(source);
|
|
130
|
+
const { checker, exports } = opened;
|
|
99
131
|
const describer = new Describer(this.ts, checker);
|
|
100
132
|
const channels = /* @__PURE__ */ new Map();
|
|
101
|
-
for (const exported of
|
|
133
|
+
for (const exported of exports) {
|
|
102
134
|
const type = checker.getTypeOfSymbol(exported);
|
|
103
135
|
if (type === void 0 || type.getSymbol()?.name !== "ChannelToken") continue;
|
|
104
136
|
const [view, commands] = checker.getTypeArguments(type);
|
|
@@ -109,6 +141,128 @@ var ContractReader = class {
|
|
|
109
141
|
warnings: describer.warnings
|
|
110
142
|
};
|
|
111
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* Every component `file` exports, described: a function whose first
|
|
146
|
+
* parameter is `Inputs<P>`, or a class extending `Component`, whose
|
|
147
|
+
* inputs are its `InputCell` fields. A library's index re-exports its
|
|
148
|
+
* components, and reading it reads all of them.
|
|
149
|
+
*/
|
|
150
|
+
readComponents(file, config) {
|
|
151
|
+
const opened = this.open(file, config);
|
|
152
|
+
if (typeof opened === "string") return {
|
|
153
|
+
components: /* @__PURE__ */ new Map(),
|
|
154
|
+
warnings: [opened]
|
|
155
|
+
};
|
|
156
|
+
const { checker, exports } = opened;
|
|
157
|
+
const describer = new Describer(this.ts, checker, "component");
|
|
158
|
+
const components = /* @__PURE__ */ new Map();
|
|
159
|
+
for (const exported of exports) {
|
|
160
|
+
const symbol = exported.flags & this.ts.SymbolFlags.Alias ? checker.getAliasedSymbol(exported) : exported;
|
|
161
|
+
const type = checker.getTypeOfSymbol(symbol);
|
|
162
|
+
const inputs = type === void 0 ? void 0 : this.inputsOf(checker, type);
|
|
163
|
+
if (inputs !== void 0) components.set(exported.name, describer.component(symbol, inputs));
|
|
164
|
+
}
|
|
165
|
+
return {
|
|
166
|
+
components,
|
|
167
|
+
warnings: describer.warnings
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* The source files of the project `config` describes, with their
|
|
172
|
+
* text: what the project itself wrote, so neither its dependencies
|
|
173
|
+
* nor declaration files. The project's own tsconfig decides what that
|
|
174
|
+
* is, which is the answer the person already gave their editor.
|
|
175
|
+
*/
|
|
176
|
+
sources(config) {
|
|
177
|
+
const program = this.snapshot({ openProjects: [config] }).getProject(config)?.program;
|
|
178
|
+
if (program === void 0) return [];
|
|
179
|
+
const out = [];
|
|
180
|
+
for (const file of program.getSourceFileNames()) {
|
|
181
|
+
if (file.includes("/node_modules/") || /\.d\.[cm]?ts$/.test(file)) continue;
|
|
182
|
+
const text = program.getSourceFile(file)?.text;
|
|
183
|
+
if (text !== void 0) out.push({
|
|
184
|
+
file,
|
|
185
|
+
text
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
return out;
|
|
189
|
+
}
|
|
190
|
+
/** The inputs a component's type declares, or undefined when it is not a component. */
|
|
191
|
+
inputsOf(checker, type) {
|
|
192
|
+
const { Call, Construct } = this.ts.SignatureKind;
|
|
193
|
+
const [call] = checker.getSignaturesOfType(type, Call);
|
|
194
|
+
const first = call?.getParameters()[0];
|
|
195
|
+
if (first !== void 0) {
|
|
196
|
+
const parameter = checker.getTypeOfSymbol(first);
|
|
197
|
+
const returns = checker.getReturnTypeOfSignature(call);
|
|
198
|
+
if (parameter?.getAliasSymbol()?.name === "Inputs" && returns !== void 0 && this.drawable(returns)) {
|
|
199
|
+
const [props] = parameter.getAliasTypeArguments();
|
|
200
|
+
return props === void 0 ? void 0 : {
|
|
201
|
+
kind: "props",
|
|
202
|
+
type: props
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
const [construct] = checker.getSignaturesOfType(type, Construct);
|
|
208
|
+
const instance = construct === void 0 ? void 0 : checker.getReturnTypeOfSignature(construct);
|
|
209
|
+
if (instance === void 0 || !this.extendsComponent(instance)) return;
|
|
210
|
+
const cells = [];
|
|
211
|
+
for (const property of checker.getPropertiesOfType(instance)) {
|
|
212
|
+
const propertyType = checker.getTypeOfSymbol(property);
|
|
213
|
+
if (propertyType?.getSymbol()?.name === "InputCell") {
|
|
214
|
+
const [value] = checker.getTypeArguments(propertyType);
|
|
215
|
+
if (value !== void 0) cells.push({
|
|
216
|
+
symbol: property,
|
|
217
|
+
type: value
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return {
|
|
222
|
+
kind: "cells",
|
|
223
|
+
cells
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
/** Whether a function returning `type` returns a child: `UiChild`, an element, or a union of them. */
|
|
227
|
+
drawable(type) {
|
|
228
|
+
if (type.getAliasSymbol()?.name === "UiChild") return true;
|
|
229
|
+
return (type.isUnionType() ? type.getTypes() ?? [] : [type]).some((member) => CHILD.has(member.getSymbol()?.name ?? ""));
|
|
230
|
+
}
|
|
231
|
+
extendsComponent(type) {
|
|
232
|
+
for (let depth = 0, current = type; current !== void 0 && depth < 16; depth++) {
|
|
233
|
+
if (current.getSymbol()?.name === "Component") return true;
|
|
234
|
+
current = current.isClassOrInterface() ? current.getBaseTypes()?.[0] : void 0;
|
|
235
|
+
}
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* The checker and the module's exports, or why there are none: read
|
|
240
|
+
* in the project `preferred` names when it includes the file (the
|
|
241
|
+
* catalog's own tsconfig, which may resolve its imports differently
|
|
242
|
+
* from any beside it), else the project TypeScript finds for it.
|
|
243
|
+
*/
|
|
244
|
+
open(file, preferred) {
|
|
245
|
+
this.changed.add(file);
|
|
246
|
+
let snapshot = this.snapshot(preferred === void 0 ? {} : { openProjects: [preferred] });
|
|
247
|
+
let config = preferred !== void 0 && snapshot.getProject(preferred)?.program.getSourceFile(file) !== void 0 ? preferred : this.configs.get(file);
|
|
248
|
+
if (config === void 0) {
|
|
249
|
+
config = this.snapshot({ openFiles: [file] }).getDefaultProjectForFile(file)?.configFileName;
|
|
250
|
+
snapshot = this.snapshot({
|
|
251
|
+
...config === void 0 ? {} : { openProjects: [config] },
|
|
252
|
+
closeFiles: [file]
|
|
253
|
+
});
|
|
254
|
+
if (config !== void 0) this.configs.set(file, config);
|
|
255
|
+
}
|
|
256
|
+
const project = config === void 0 ? void 0 : snapshot.getProject(config);
|
|
257
|
+
const source = project?.program.getSourceFile(file);
|
|
258
|
+
if (project === void 0 || source === void 0) return `TypeScript has no project that includes ${file}.`;
|
|
259
|
+
const checker = project.checker;
|
|
260
|
+
const module = checker.getSymbolAtLocation(source);
|
|
261
|
+
return {
|
|
262
|
+
checker,
|
|
263
|
+
exports: module === void 0 ? [] : checker.getExportsOfModule(module)
|
|
264
|
+
};
|
|
265
|
+
}
|
|
112
266
|
close() {
|
|
113
267
|
this.api?.close();
|
|
114
268
|
this.api = null;
|
|
@@ -175,7 +329,27 @@ const BINARY = /* @__PURE__ */ new Set([
|
|
|
175
329
|
"BigInt64Array",
|
|
176
330
|
"BigUint64Array"
|
|
177
331
|
]);
|
|
178
|
-
/**
|
|
332
|
+
/**
|
|
333
|
+
* The types a component takes as a child. `UiChild` is a union of
|
|
334
|
+
* these and an Observable of them, and describing its members would
|
|
335
|
+
* describe the element records a tag compiles to, which nobody writes.
|
|
336
|
+
*/
|
|
337
|
+
const CHILD = /* @__PURE__ */ new Set([
|
|
338
|
+
"UiElement",
|
|
339
|
+
"ComponentLikeElement",
|
|
340
|
+
"ComponentElement"
|
|
341
|
+
]);
|
|
342
|
+
/**
|
|
343
|
+
* Turns checker types into JSON Schema for one module's channels or
|
|
344
|
+
* components.
|
|
345
|
+
*
|
|
346
|
+
* The two differ in what is allowed. A channel's values cross a thread
|
|
347
|
+
* as plain data, so a function or a class instance in one is a mistake,
|
|
348
|
+
* and is reported. A component's inputs stay on the render thread, where
|
|
349
|
+
* a callback is how a component talks back and a child is how it is
|
|
350
|
+
* composed, so there they are described for what they are and nothing
|
|
351
|
+
* is reported.
|
|
352
|
+
*/
|
|
179
353
|
var Describer = class {
|
|
180
354
|
warnings = [];
|
|
181
355
|
flags;
|
|
@@ -188,12 +362,86 @@ var Describer = class {
|
|
|
188
362
|
/** `$defs` for the schema being built. Reset per root, so each schema stands alone. */
|
|
189
363
|
defs = /* @__PURE__ */ new Map();
|
|
190
364
|
defNames = /* @__PURE__ */ new Map();
|
|
365
|
+
/** In a component, each named type's `$defs` entry, or null when it is small enough to repeat. */
|
|
366
|
+
shared = /* @__PURE__ */ new Map();
|
|
191
367
|
ts;
|
|
192
368
|
checker;
|
|
193
|
-
|
|
369
|
+
mode;
|
|
370
|
+
constructor(ts, checker, mode = "channel") {
|
|
194
371
|
this.ts = ts;
|
|
195
372
|
this.checker = checker;
|
|
196
373
|
this.flags = ts.TypeFlags;
|
|
374
|
+
this.mode = mode;
|
|
375
|
+
}
|
|
376
|
+
component(symbol, inputs) {
|
|
377
|
+
this.defs = /* @__PURE__ */ new Map();
|
|
378
|
+
this.shared = /* @__PURE__ */ new Map();
|
|
379
|
+
const checker = this.checker;
|
|
380
|
+
const properties = {};
|
|
381
|
+
const required = [];
|
|
382
|
+
const entries = inputs.kind === "cells" ? inputs.cells : checker.getPropertiesOfType(inputs.type).map((property) => ({
|
|
383
|
+
symbol: property,
|
|
384
|
+
type: checker.getTypeOfSymbol(property)
|
|
385
|
+
}));
|
|
386
|
+
const own = inputs.kind === "props" ? (inputs.type.getAliasSymbol() ?? inputs.type.getSymbol())?.name : void 0;
|
|
387
|
+
for (const { symbol: property, type: given } of entries) {
|
|
388
|
+
const path = `${symbol.name}.${property.name}`;
|
|
389
|
+
const type = given !== void 0 && this.includesUndefined(given) && !this.includesNull(given) ? checker.getNonNullableType(given) ?? given : given;
|
|
390
|
+
let schema = type === void 0 ? {} : this.describe(type, path);
|
|
391
|
+
if (type !== void 0) schema = {
|
|
392
|
+
...schema,
|
|
393
|
+
"x-gesso-type": this.typeText(type)
|
|
394
|
+
};
|
|
395
|
+
const description = checker.getDocumentationCommentOfSymbol(property);
|
|
396
|
+
if (description !== "") schema.description = description;
|
|
397
|
+
const fallback = checker.getJsDocTagsOfSymbol(property).find((tag) => tag.name === "default");
|
|
398
|
+
if (fallback?.text !== void 0) schema.default = parseDefault(fallback.text);
|
|
399
|
+
const from = property.getParent()?.name;
|
|
400
|
+
if (own !== void 0 && from !== void 0 && from !== own && !from.startsWith("__")) schema["x-gesso-from"] = from;
|
|
401
|
+
properties[property.name] = schema;
|
|
402
|
+
if (!(inputs.kind === "cells" || (property.flags & this.ts.SymbolFlags.Optional) !== 0 || given !== void 0 && this.includesUndefined(given))) required.push(property.name);
|
|
403
|
+
}
|
|
404
|
+
const schema = {
|
|
405
|
+
type: "object",
|
|
406
|
+
properties,
|
|
407
|
+
additionalProperties: false
|
|
408
|
+
};
|
|
409
|
+
if (required.length > 0) schema.required = required;
|
|
410
|
+
if (this.defs.size > 0) schema.$defs = Object.fromEntries(this.defs);
|
|
411
|
+
const out = { inputs: schema };
|
|
412
|
+
const description = this.componentDocumentation(symbol, inputs);
|
|
413
|
+
if (description !== "") {
|
|
414
|
+
out.summary = description.split(/\n\s*\n/)[0].replace(/\s+/g, " ").trim();
|
|
415
|
+
out.description = description;
|
|
416
|
+
}
|
|
417
|
+
const tags = checker.getJsDocTagsOfSymbol(symbol);
|
|
418
|
+
const examples = tags.filter((tag) => tag.name === "example" && tag.text !== void 0).map((tag) => tag.text);
|
|
419
|
+
if (examples.length > 0) out.examples = examples;
|
|
420
|
+
const deprecated = tags.find((tag) => tag.name === "deprecated");
|
|
421
|
+
if (deprecated !== void 0) out.deprecated = deprecated.text === void 0 || deprecated.text.trim() === "" ? true : deprecated.text.trim();
|
|
422
|
+
return out;
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* What a component is for: its own JSDoc, else its props type's. A
|
|
426
|
+
* comment elsewhere in its file is not read: no rule about which one
|
|
427
|
+
* describes the component holds across files, and a summary that is
|
|
428
|
+
* sometimes about something else is worse to an agent than none.
|
|
429
|
+
*/
|
|
430
|
+
componentDocumentation(symbol, inputs) {
|
|
431
|
+
const own = this.checker.getDocumentationCommentOfSymbol(symbol);
|
|
432
|
+
if (own !== "") return own;
|
|
433
|
+
const props = inputs.kind === "props" ? inputs.type.getAliasSymbol() ?? inputs.type.getSymbol() : void 0;
|
|
434
|
+
return props === void 0 ? "" : this.checker.getDocumentationCommentOfSymbol(props);
|
|
435
|
+
}
|
|
436
|
+
/** The type as TypeScript writes it, without the `undefined` an optional input carries. */
|
|
437
|
+
typeText(type) {
|
|
438
|
+
const defined = this.includesUndefined(type) ? this.checker.getNonNullableType(type) : type;
|
|
439
|
+
const text = this.checker.typeToString(defined ?? type);
|
|
440
|
+
return this.includesNull(type) && !/\bnull\b/.test(text) ? `${text} | null` : text;
|
|
441
|
+
}
|
|
442
|
+
includesNull(type) {
|
|
443
|
+
const isNull = (member) => (member.flags & this.flags.Null) !== 0;
|
|
444
|
+
return type.isUnionType() ? (type.getTypes() ?? []).some(isNull) : isNull(type);
|
|
197
445
|
}
|
|
198
446
|
channel(token, view, commands) {
|
|
199
447
|
const out = {
|
|
@@ -293,7 +541,30 @@ var Describer = class {
|
|
|
293
541
|
if (type.isUnionType()) return (type.getTypes() ?? []).some((member) => (member.flags & (Undefined | Void)) !== 0);
|
|
294
542
|
return (type.flags & (Undefined | Void)) !== 0;
|
|
295
543
|
}
|
|
544
|
+
/**
|
|
545
|
+
* In a component, a named type an input uses (`UiLength`, a props
|
|
546
|
+
* interface) is described once, in `$defs`, and referred to after.
|
|
547
|
+
* Every control takes the same layout inputs, and spelled out at each
|
|
548
|
+
* use they were most of each component's description: an agent reads
|
|
549
|
+
* these, and pays for every repetition.
|
|
550
|
+
*/
|
|
296
551
|
describe(type, path) {
|
|
552
|
+
if (this.mode !== "component") return this.describeType(type, path);
|
|
553
|
+
const known = this.shared.get(type.id);
|
|
554
|
+
if (known !== void 0) return known === null ? this.describeType(type, path) : { $ref: `#/$defs/${known}` };
|
|
555
|
+
const name = (type.getAliasSymbol() ?? type.getSymbol())?.name;
|
|
556
|
+
if (name === void 0 || name.startsWith("__") || name === "Array" || name === "ReadonlyArray") return this.describeType(type, path);
|
|
557
|
+
const schema = this.describeType(type, path);
|
|
558
|
+
if (schema.$ref !== void 0 || isSmall(schema)) {
|
|
559
|
+
this.shared.set(type.id, null);
|
|
560
|
+
return schema;
|
|
561
|
+
}
|
|
562
|
+
const defName = this.defName(type);
|
|
563
|
+
this.defs.set(defName, schema);
|
|
564
|
+
this.shared.set(type.id, defName);
|
|
565
|
+
return { $ref: `#/$defs/${defName}` };
|
|
566
|
+
}
|
|
567
|
+
describeType(type, path) {
|
|
297
568
|
const f = this.flags;
|
|
298
569
|
const flags = type.flags;
|
|
299
570
|
if (flags & (f.Any | f.Unknown)) return {};
|
|
@@ -333,6 +604,7 @@ var Describer = class {
|
|
|
333
604
|
union(type, path) {
|
|
334
605
|
const f = this.flags;
|
|
335
606
|
let members = (type.getTypes() ?? []).filter((member) => (member.flags & (f.Undefined | f.Void)) === 0);
|
|
607
|
+
if (this.mode === "component" && members.some((member) => CHILD.has(member.getSymbol()?.name ?? ""))) return { "x-gesso-child": true };
|
|
336
608
|
const booleans = members.filter((member) => member.flags & f.BooleanLiteral);
|
|
337
609
|
const schemas = [];
|
|
338
610
|
if (booleans.length === 2) {
|
|
@@ -376,6 +648,11 @@ var Describer = class {
|
|
|
376
648
|
object(type, path) {
|
|
377
649
|
const checker = this.checker;
|
|
378
650
|
const symbolName = type.getSymbol()?.name;
|
|
651
|
+
if (this.mode === "component") {
|
|
652
|
+
if (symbolName !== void 0 && CHILD.has(symbolName)) return { "x-gesso-child": true };
|
|
653
|
+
if (checker.getSignaturesOfType(type, this.ts.SignatureKind.Call).length > 0) return { "x-gesso-callback": true };
|
|
654
|
+
if (symbolName !== void 0 && NOT_PLAIN.has(symbolName) || ((type.getSymbol()?.flags ?? 0) & this.ts.SymbolFlags.Class) !== 0) return { "x-gesso-type": checker.typeToString(type) };
|
|
655
|
+
}
|
|
379
656
|
if (symbolName !== void 0 && this.inCommand && BINARY.has(symbolName)) return {
|
|
380
657
|
type: "string",
|
|
381
658
|
contentEncoding: "base64",
|
|
@@ -438,10 +715,31 @@ var Describer = class {
|
|
|
438
715
|
};
|
|
439
716
|
}
|
|
440
717
|
unplain(path, what) {
|
|
718
|
+
if (this.mode === "component") return {};
|
|
441
719
|
this.warnings.push(`${path} is ${what}, which is not plain data and cannot cross a channel.`);
|
|
442
720
|
return {};
|
|
443
721
|
}
|
|
444
722
|
};
|
|
723
|
+
/**
|
|
724
|
+
* A `@default` tag's value: JSON when it is JSON (`99`, `'neutral'`
|
|
725
|
+
* written with double quotes, `true`), a single-quoted string unquoted,
|
|
726
|
+
* and otherwise the text as written.
|
|
727
|
+
*/
|
|
728
|
+
function parseDefault(text) {
|
|
729
|
+
const trimmed = text.trim();
|
|
730
|
+
try {
|
|
731
|
+
return JSON.parse(trimmed);
|
|
732
|
+
} catch {
|
|
733
|
+
const quoted = /^'(.*)'$/.exec(trimmed) ?? /^`(.*)`$/.exec(trimmed);
|
|
734
|
+
return quoted === null ? trimmed : quoted[1];
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
/** Whether a schema is as short as a reference to it would be. */
|
|
738
|
+
function isSmall(schema) {
|
|
739
|
+
if (schema.enum !== void 0 || schema.const !== void 0) return true;
|
|
740
|
+
const keys = Object.keys(schema);
|
|
741
|
+
return keys.length === 0 || keys.length === 1 && (typeof schema.type === "string" || keys[0].startsWith("x-gesso-"));
|
|
742
|
+
}
|
|
445
743
|
//#endregion
|
|
446
744
|
//#region bin/gesso-channels.ts
|
|
447
745
|
/**
|