sveld 0.10.1 → 0.12.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 CHANGED
@@ -10,6 +10,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
10
10
  - add isAccessor field to API
11
11
  - update Markdown writer to generate a separate table for accessors
12
12
 
13
+ ## [0.12.0](https://github.com/carbon-design-system/sveld/releases/tag/v0.12.0) - 2022-01-02
14
+
15
+ - support props defined via renamed exports (i.e.m `let className; export { className as class }`)
16
+
17
+ ## [0.11.1](https://github.com/carbon-design-system/sveld/releases/tag/v0.11.1) - 2021-12-31
18
+
19
+ - replace backslashes with forward slashes in COMPONENT_API.json `filePath` values
20
+
21
+ ## [0.11.0](https://github.com/carbon-design-system/sveld/releases/tag/v0.11.0) - 2021-12-16
22
+
23
+ - support writing `<!-- @component -->` comments in Svelte components to TypeScript definitions
24
+
25
+ ## [0.10.2](https://github.com/carbon-design-system/sveld/releases/tag/v0.10.2) - 2021-08-29
26
+
27
+ - tolerate slot spread syntax (`<slot {...props} />`) when parsing Svelte components
28
+
13
29
  ## [0.10.1](https://github.com/carbon-design-system/sveld/releases/tag/v0.10.1) - 2021-08-28
14
30
 
15
31
  - include `.svelte` extension in `index.d.ts` exports
package/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # sveld
2
2
 
3
3
  [![NPM][npm]][npm-url]
4
- [![Build][build]][build-badge]
4
+ ![GitHub](https://img.shields.io/github/license/carbon-design-system/sveld?color=262626&style=for-the-badge)
5
+ ![npm downloads to date](https://img.shields.io/npm/dt/sveld?color=262626&style=for-the-badge)
5
6
 
6
7
  `sveld` generates TypeScript definitions for Svelte components by statically analyzing their props, events, slots and more. Prop types and signatures can be defined using [JSDoc notation](https://jsdoc.app/). This documentation generator can also emit component documentation in Markdown and JSON output formats.
7
8
 
@@ -13,7 +14,7 @@ The purpose of this project is to make third party Svelte component libraries co
13
14
  - [Component Index](https://github.com/IBM/carbon-components-svelte/blob/master/COMPONENT_INDEX.md): Markdown file documenting component props, slots, and events
14
15
  - [Component API](https://github.com/IBM/carbon-components-svelte/blob/master/docs/src/COMPONENT_API.json): Component API metadata in JSON format
15
16
 
16
- **Please note** that the generated TypeScript definitions require [Svelte version 3.31](https://github.com/sveltejs/svelte/blob/master/CHANGELOG.md#3300) or greater.
17
+ **Please note** that the generated TypeScript definitions require [Svelte version 3.31](https://github.com/sveltejs/svelte/blob/master/CHANGELOG.md#3310) or greater.
17
18
 
18
19
  ---
19
20
 
@@ -399,13 +400,45 @@ Signature:
399
400
  Example:
400
401
 
401
402
  ```js
402
- /** @extends {"./Button"} ButtonProps */
403
+ /** @extends {"./Button.svelte"} ButtonProps */
403
404
 
404
405
  export const secondary = true;
405
406
 
406
407
  import Button from "./Button.svelte";
407
408
  ```
408
409
 
410
+ ### `@component` comments
411
+
412
+ The Svelte Language Server supports component-level comments through the following syntax: `<!-- @component [comment] -->`.
413
+
414
+ `sveld` will copy these over to the exported default component in the TypeScript definition.
415
+
416
+ Example:
417
+
418
+ ```svelte
419
+ <!-- @component
420
+ @example
421
+ <Button>
422
+ Text
423
+ </Button>
424
+ -->
425
+ <button>
426
+ <slot />
427
+ </button>
428
+ ```
429
+
430
+ Output:
431
+
432
+ ```ts
433
+ /**
434
+ * @example
435
+ * <Button>
436
+ * Text
437
+ * </Button>
438
+ */
439
+ export default class Button extends SvelteComponentTyped<ButtonProps, {}, { default: {} }> {}
440
+ ```
441
+
409
442
  ## Contributing
410
443
 
411
444
  Refer to the [contributing guidelines](CONTRIBUTING.md).
@@ -416,5 +449,3 @@ Refer to the [contributing guidelines](CONTRIBUTING.md).
416
449
 
417
450
  [npm]: https://img.shields.io/npm/v/sveld.svg?color=262626&style=for-the-badge
418
451
  [npm-url]: https://npmjs.com/package/sveld
419
- [build]: https://img.shields.io/travis/com/ibm/sveld?color=24a148&style=for-the-badge
420
- [build-badge]: https://travis-ci.com/ibm/sveld
@@ -58,6 +58,7 @@ export interface ParsedComponent {
58
58
  typedefs: TypeDef[];
59
59
  rest_props: RestProps;
60
60
  extends?: Extends;
61
+ componentComment?: string;
61
62
  }
62
63
  export default class ComponentParser {
63
64
  private options?;
@@ -65,7 +66,9 @@ export default class ComponentParser {
65
66
  private compiled?;
66
67
  private rest_props?;
67
68
  private extends?;
69
+ private componentComment?;
68
70
  private readonly reactive_vars;
71
+ private readonly vars;
69
72
  private readonly props;
70
73
  private readonly slots;
71
74
  private readonly events;
@@ -27,6 +27,7 @@ var DEFAULT_SLOT_NAME = "__default__";
27
27
  var ComponentParser = /** @class */ (function () {
28
28
  function ComponentParser(options) {
29
29
  this.reactive_vars = new Set();
30
+ this.vars = new Set();
30
31
  this.props = new Map();
31
32
  this.slots = new Map();
32
33
  this.events = new Map();
@@ -160,6 +161,7 @@ var ComponentParser = /** @class */ (function () {
160
161
  this.compiled = undefined;
161
162
  this.rest_props = undefined;
162
163
  this["extends"] = undefined;
164
+ this.componentComment = undefined;
163
165
  this.reactive_vars.clear();
164
166
  this.props.clear();
165
167
  this.slots.clear();
@@ -182,7 +184,7 @@ var ComponentParser = /** @class */ (function () {
182
184
  var callees = [];
183
185
  (0, compiler_1.walk)(this.compiled.ast, {
184
186
  enter: function (node, parent, prop) {
185
- var _a, _b, _c, _d, _e, _f, _g, _h;
187
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
186
188
  if (node.type === "CallExpression") {
187
189
  if (node.callee.name === "createEventDispatcher") {
188
190
  dispatcher_name = parent === null || parent === void 0 ? void 0 : parent.id.name;
@@ -200,11 +202,28 @@ var ComponentParser = /** @class */ (function () {
200
202
  };
201
203
  }
202
204
  }
203
- if (node.type === "ExportNamedDeclaration" && node.declaration != null) {
204
- var _j = node.declaration.declarations
205
- ? node.declaration.declarations[0]
206
- : node.declaration, declaration_type = _j.type, id = _j.id, init = _j.init, body = _j.body;
207
- var prop_name = id.name;
205
+ if (node.type === "VariableDeclaration") {
206
+ _this.vars.add(node);
207
+ }
208
+ if (node.type === "ExportNamedDeclaration") {
209
+ // Handle renamed exports
210
+ var prop_name = void 0;
211
+ if (node.declaration == null && ((_a = node.specifiers[0]) === null || _a === void 0 ? void 0 : _a.type) === "ExportSpecifier") {
212
+ var specifier = node.specifiers[0];
213
+ var localName_1 = specifier.local.name, exportedName = specifier.exported.name;
214
+ var declaration_1;
215
+ // Search through all variable declarations for this variable
216
+ // Limitation: the variable must have been declared before the export
217
+ _this.vars.forEach(function (varDecl) {
218
+ if (varDecl.declarations.some(function (decl) { return decl.id.type === "Identifier" && decl.id.name === localName_1; })) {
219
+ declaration_1 = varDecl;
220
+ }
221
+ });
222
+ node.declaration = declaration_1;
223
+ prop_name = exportedName;
224
+ }
225
+ var _m = node.declaration.declarations ? node.declaration.declarations[0] : node.declaration, declaration_type = _m.type, id = _m.id, init = _m.init, body = _m.body;
226
+ prop_name !== null && prop_name !== void 0 ? prop_name : (prop_name = id.name);
208
227
  var value = undefined;
209
228
  var type = undefined;
210
229
  var kind = node.declaration.kind;
@@ -216,7 +235,7 @@ var ComponentParser = /** @class */ (function () {
216
235
  init.type === "BinaryExpression" ||
217
236
  init.type === "ArrayExpression" ||
218
237
  init.type === "ArrowFunctionExpression") {
219
- value = (_a = _this.sourceAtPos(init.start, init.end)) === null || _a === void 0 ? void 0 : _a.replace(/\n/g, " ");
238
+ value = (_b = _this.sourceAtPos(init.start, init.end)) === null || _b === void 0 ? void 0 : _b.replace(/\n/g, " ");
220
239
  type = value;
221
240
  isFunction = init.type === "ArrowFunctionExpression";
222
241
  if (init.type === "BinaryExpression") {
@@ -228,7 +247,7 @@ var ComponentParser = /** @class */ (function () {
228
247
  else {
229
248
  if (init.type === "UnaryExpression") {
230
249
  value = _this.sourceAtPos(init.start, init.end);
231
- type = typeof ((_b = init.argument) === null || _b === void 0 ? void 0 : _b.value);
250
+ type = typeof ((_c = init.argument) === null || _c === void 0 ? void 0 : _c.value);
232
251
  }
233
252
  else {
234
253
  value = init.raw;
@@ -237,7 +256,7 @@ var ComponentParser = /** @class */ (function () {
237
256
  }
238
257
  }
239
258
  if (declaration_type === "FunctionDeclaration") {
240
- value = "() => " + ((_c = _this.sourceAtPos(body.start, body.end)) === null || _c === void 0 ? void 0 : _c.replace(/\n/g, " "));
259
+ value = "() => " + ((_d = _this.sourceAtPos(body.start, body.end)) === null || _d === void 0 ? void 0 : _d.replace(/\n/g, " "));
241
260
  type = "() => any";
242
261
  kind = "function";
243
262
  isFunction = true;
@@ -246,10 +265,10 @@ var ComponentParser = /** @class */ (function () {
246
265
  if (node.leadingComments) {
247
266
  var last_comment = node.leadingComments[node.leadingComments.length - 1];
248
267
  var comment = commentParser(ComponentParser.formatComment(last_comment.value));
249
- var tag = (_d = comment[0]) === null || _d === void 0 ? void 0 : _d.tags[((_e = comment[0]) === null || _e === void 0 ? void 0 : _e.tags.length) - 1];
268
+ var tag = (_e = comment[0]) === null || _e === void 0 ? void 0 : _e.tags[((_f = comment[0]) === null || _f === void 0 ? void 0 : _f.tags.length) - 1];
250
269
  if ((tag === null || tag === void 0 ? void 0 : tag.tag) === "type")
251
270
  type = _this.aliasType(tag.type);
252
- description = ComponentParser.assignValue((_f = comment[0]) === null || _f === void 0 ? void 0 : _f.description);
271
+ description = ComponentParser.assignValue((_g = comment[0]) === null || _g === void 0 ? void 0 : _g.description);
253
272
  }
254
273
  if (!description && _this.typedefs.has(type)) {
255
274
  description = _this.typedefs.get(type).description;
@@ -266,8 +285,14 @@ var ComponentParser = /** @class */ (function () {
266
285
  reactive: _this.reactive_vars.has(prop_name)
267
286
  });
268
287
  }
288
+ if (node.type === "Comment") {
289
+ var data = (_j = (_h = node === null || node === void 0 ? void 0 : node.data) === null || _h === void 0 ? void 0 : _h.trim()) !== null && _j !== void 0 ? _j : "";
290
+ if (/^@component/.test(data)) {
291
+ _this.componentComment = data.replace(/^@component/, "");
292
+ }
293
+ }
269
294
  if (node.type === "Slot") {
270
- var slot_name = (_g = node.attributes.find(function (attr) { return attr.name === "name"; })) === null || _g === void 0 ? void 0 : _g.value[0].data;
295
+ var slot_name = (_k = node.attributes.find(function (attr) { return attr.name === "name"; })) === null || _k === void 0 ? void 0 : _k.value[0].data;
271
296
  var slot_props = node.attributes
272
297
  .filter(function (attr) { return attr.name !== "name"; })
273
298
  .reduce(function (slot_props, _a) {
@@ -277,6 +302,8 @@ var ComponentParser = /** @class */ (function () {
277
302
  value: undefined,
278
303
  replace: false
279
304
  };
305
+ if (value === undefined)
306
+ return {};
280
307
  if (value[0]) {
281
308
  var _c = value[0], type = _c.type, expression = _c.expression, raw = _c.raw, start = _c.start, end = _c.end;
282
309
  if (type === "Text") {
@@ -302,7 +329,7 @@ var ComponentParser = /** @class */ (function () {
302
329
  }
303
330
  return __assign(__assign({}, slot_props), (_b = {}, _b[name] = slot_prop_value, _b));
304
331
  }, {});
305
- var fallback = (_h = node.children) === null || _h === void 0 ? void 0 : _h.map(function (_a) {
332
+ var fallback = (_l = node.children) === null || _l === void 0 ? void 0 : _l.map(function (_a) {
306
333
  var start = _a.start, end = _a.end;
307
334
  return _this.sourceAtPos(start, end);
308
335
  }).join("").trim();
@@ -387,7 +414,8 @@ var ComponentParser = /** @class */ (function () {
387
414
  events: ComponentParser.mapToArray(this.events),
388
415
  typedefs: ComponentParser.mapToArray(this.typedefs),
389
416
  rest_props: this.rest_props,
390
- "extends": this["extends"]
417
+ "extends": this["extends"],
418
+ componentComment: this.componentComment
391
419
  };
392
420
  };
393
421
  return ComponentParser;
package/lib/path.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Normalize directory separators to always use `/`.
3
+ * @param filePath A file path.
4
+ * @returns Path with normalized separators.
5
+ */
6
+ export declare function normalizeSeparators(filePath: string): string;
package/lib/path.js ADDED
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ exports.__esModule = true;
3
+ exports.normalizeSeparators = void 0;
4
+ var path_1 = require("path");
5
+ /**
6
+ * Normalize directory separators to always use `/`.
7
+ * @param filePath A file path.
8
+ * @returns Path with normalized separators.
9
+ */
10
+ function normalizeSeparators(filePath) {
11
+ return path_1.sep === "/" ? filePath : filePath.split(path_1.sep).join("/");
12
+ }
13
+ exports.normalizeSeparators = normalizeSeparators;
@@ -59,6 +59,7 @@ var get_svelte_entry_1 = require("./get-svelte-entry");
59
59
  var parse_exports_1 = require("./parse-exports");
60
60
  var compiler_1 = require("svelte/compiler");
61
61
  var svelte_preprocess_1 = require("svelte-preprocess");
62
+ var path_1 = require("./path");
62
63
  function pluginSveld(opts) {
63
64
  var result;
64
65
  var input;
@@ -101,10 +102,7 @@ function generateBundle(input, glob) {
101
102
  if (glob) {
102
103
  fg.sync([dir + "/**/*.svelte"]).forEach(function (file) {
103
104
  var moduleName = path.parse(file).name.replace(/\-/g, "");
104
- var source = "./" + path.relative(dir, file);
105
- if (path.sep !== "/") {
106
- source = source.split(path.sep).join("/");
107
- }
105
+ var source = (0, path_1.normalizeSeparators)("./" + path.relative(dir, file));
108
106
  if (exports[moduleName]) {
109
107
  exports[moduleName].source = source;
110
108
  }
@@ -48,6 +48,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
48
48
  };
49
49
  exports.__esModule = true;
50
50
  var path = require("path");
51
+ var path_1 = require("../path");
51
52
  var Writer_1 = require("./Writer");
52
53
  function writeJson(components, options) {
53
54
  return __awaiter(this, void 0, void 0, function () {
@@ -59,7 +60,7 @@ function writeJson(components, options) {
59
60
  total: components.size,
60
61
  components: Array.from(components, function (_a) {
61
62
  var moduleName = _a[0], component = _a[1];
62
- return (__assign(__assign({}, component), { filePath: path.join(options.inputDir, path.normalize(component.filePath)) }));
63
+ return (__assign(__assign({}, component), { filePath: (0, path_1.normalizeSeparators)(path.join(options.inputDir, path.normalize(component.filePath))) }));
63
64
  }).sort(function (a, b) {
64
65
  if (a.moduleName < b.moduleName)
65
66
  return -1;
@@ -148,15 +148,25 @@ function genImports(def) {
148
148
  return "";
149
149
  return "import { " + def["extends"].interface + " } from " + def["extends"]["import"] + ";";
150
150
  }
151
+ function genComponentComment(def) {
152
+ if (!def.componentComment)
153
+ return "";
154
+ if (!/\n/.test(def.componentComment))
155
+ return "/** " + def.componentComment.trim() + " */";
156
+ return "/*" + def.componentComment
157
+ .split("\n")
158
+ .map(function (line) { return "* " + line; })
159
+ .join("\n") + "\n*/";
160
+ }
151
161
  function writeTsDefinition(component) {
152
- var moduleName = component.moduleName, typedefs = component.typedefs, props = component.props, slots = component.slots, events = component.events, rest_props = component.rest_props, _extends = component["extends"];
162
+ var moduleName = component.moduleName, typedefs = component.typedefs, props = component.props, slots = component.slots, events = component.events, rest_props = component.rest_props, _extends = component["extends"], componentComment = component.componentComment;
153
163
  var _a = genPropDef({
154
164
  moduleName: moduleName,
155
165
  props: props,
156
166
  rest_props: rest_props,
157
167
  "extends": _extends
158
168
  }), props_name = _a.props_name, prop_def = _a.prop_def;
159
- return "\n /// <reference types=\"svelte\" />\n import { SvelteComponentTyped } from \"svelte\";\n " + genImports({ "extends": _extends }) + "\n " + getTypeDefs({ typedefs: typedefs }) + "\n " + prop_def + "\n\n export default class " + (moduleName === "default" ? "" : moduleName) + " extends SvelteComponentTyped<\n " + props_name + ",\n {" + genEventDef({ events: events }) + "},\n {" + genSlotDef({ slots: slots }) + "}\n > {\n " + genAccessors({ props: props }) + "\n }";
169
+ return "\n /// <reference types=\"svelte\" />\n import { SvelteComponentTyped } from \"svelte\";\n " + genImports({ "extends": _extends }) + "\n " + getTypeDefs({ typedefs: typedefs }) + "\n " + prop_def + "\n " + genComponentComment({ componentComment: componentComment }) + "\n export default class " + (moduleName === "default" ? "" : moduleName) + " extends SvelteComponentTyped<\n " + props_name + ",\n {" + genEventDef({ events: events }) + "},\n {" + genSlotDef({ slots: slots }) + "}\n > {\n " + genAccessors({ props: props }) + "\n }";
160
170
  }
161
171
  exports.writeTsDefinition = writeTsDefinition;
162
172
  function writeTsDefinitions(components, options) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sveld",
3
- "version": "0.10.1",
3
+ "version": "0.12.0",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Generate TypeScript definitions for your Svelte components.",
6
6
  "main": "./lib/index.js",
@@ -11,7 +11,7 @@
11
11
  "test": "run-p test:*",
12
12
  "test:unit": "tsnd node_modules/tape/bin/tape tests/*.test.ts",
13
13
  "test:integration": "node tests/integration",
14
- "format": "prettier --write '{src,tests}/**/*.ts'",
14
+ "format": "prettier --write \"{src,tests}/**/*.{ts,svelte}\"",
15
15
  "prepack": "run-s build test"
16
16
  },
17
17
  "peerDependencies": {
@@ -36,6 +36,7 @@
36
36
  "@types/prettier": "^2.3.2",
37
37
  "@types/tape": "^4.13.2",
38
38
  "npm-run-all": "^4.1.5",
39
+ "prettier-plugin-svelte": "^2.4.0",
39
40
  "tape": "^5.3.1",
40
41
  "ts-node-dev": "^1.1.1"
41
42
  },