cem-plugin-wrec 0.2.0 → 0.2.2

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.
@@ -0,0 +1,8 @@
1
+ import wrecPlugin from "./index.js";
2
+
3
+ export default {
4
+ exclude: ["node_modules"],
5
+ //dev: true, // for extra logging
6
+ globs: ["fixtures/**/*.js"],
7
+ plugins: [wrecPlugin()],
8
+ };
@@ -0,0 +1,159 @@
1
+ {
2
+ "schemaVersion": "1.0.0",
3
+ "readme": "",
4
+ "modules": [
5
+ {
6
+ "kind": "javascript-module",
7
+ "path": "fixtures/hello-wrec.js",
8
+ "declarations": [
9
+ {
10
+ "kind": "class",
11
+ "description": "This displays a greeting message for a given name in a specified color.",
12
+ "name": "HelloWrec",
13
+ "cssProperties": [
14
+ {
15
+ "description": "color of border that surrounds the component",
16
+ "name": "--border-color",
17
+ "default": "gray"
18
+ }
19
+ ],
20
+ "cssParts": [
21
+ {
22
+ "description": "greeting message",
23
+ "name": "greeting"
24
+ }
25
+ ],
26
+ "slots": [
27
+ {
28
+ "description": "for content after the greeting",
29
+ "name": ""
30
+ },
31
+ {
32
+ "description": "for content before the greeting",
33
+ "name": "before"
34
+ },
35
+ {
36
+ "description": "for content after the greeting and the unnamed slot",
37
+ "name": "after"
38
+ }
39
+ ],
40
+ "members": [
41
+ {
42
+ "kind": "field",
43
+ "name": "color",
44
+ "privacy": "public",
45
+ "type": {
46
+ "text": "string"
47
+ },
48
+ "attribute": "color",
49
+ "default": "black",
50
+ "description": "text color",
51
+ "reflects": true
52
+ },
53
+ {
54
+ "kind": "field",
55
+ "name": "name",
56
+ "privacy": "public",
57
+ "type": {
58
+ "text": "string"
59
+ },
60
+ "attribute": "name",
61
+ "default": "World",
62
+ "description": "name to greet",
63
+ "reflects": true
64
+ }
65
+ ],
66
+ "attributes": [
67
+ {
68
+ "name": "color",
69
+ "type": {
70
+ "text": "string"
71
+ },
72
+ "fieldName": "color",
73
+ "default": "black",
74
+ "description": "text color"
75
+ },
76
+ {
77
+ "name": "name",
78
+ "type": {
79
+ "text": "string"
80
+ },
81
+ "fieldName": "name",
82
+ "default": "World",
83
+ "description": "name to greet"
84
+ }
85
+ ],
86
+ "superclass": {
87
+ "name": "Wrec",
88
+ "package": "wrec"
89
+ },
90
+ "summary": "This displays a greeting message.",
91
+ "tagName": "hello-wrec",
92
+ "customElement": true
93
+ }
94
+ ],
95
+ "exports": [
96
+ {
97
+ "kind": "custom-element-definition",
98
+ "name": "hello-wrec",
99
+ "declaration": {
100
+ "name": "HelloWrec",
101
+ "module": "fixtures/hello-wrec.js"
102
+ }
103
+ }
104
+ ]
105
+ },
106
+ {
107
+ "kind": "javascript-module",
108
+ "path": "fixtures/my-counter.js",
109
+ "declarations": [
110
+ {
111
+ "kind": "class",
112
+ "description": "This is a counter web component implemented with wrec.",
113
+ "name": "CounterWrec",
114
+ "members": [
115
+ {
116
+ "kind": "field",
117
+ "name": "count",
118
+ "privacy": "public",
119
+ "type": {
120
+ "text": "number"
121
+ },
122
+ "attribute": "count",
123
+ "default": 0,
124
+ "description": "initial value",
125
+ "reflects": true
126
+ }
127
+ ],
128
+ "attributes": [
129
+ {
130
+ "name": "count",
131
+ "type": {
132
+ "text": "number"
133
+ },
134
+ "fieldName": "count",
135
+ "default": 0,
136
+ "description": "initial value"
137
+ }
138
+ ],
139
+ "superclass": {
140
+ "name": "Wrec",
141
+ "package": "wrec"
142
+ },
143
+ "tagName": "counter-wrec",
144
+ "customElement": true
145
+ }
146
+ ],
147
+ "exports": [
148
+ {
149
+ "kind": "custom-element-definition",
150
+ "name": "counter-wrec",
151
+ "declaration": {
152
+ "name": "CounterWrec",
153
+ "module": "fixtures/my-counter.js"
154
+ }
155
+ }
156
+ ]
157
+ }
158
+ ]
159
+ }
@@ -0,0 +1,40 @@
1
+ import { css, html, Wrec } from "wrec";
2
+
3
+ //TODO: The analyzer is not generating proper documentation for this component!
4
+
5
+ /**
6
+ * This displays a greeting message for a given name in a specified color.
7
+ * @summary This displays a greeting message.
8
+ * @slot - for content after the greeting
9
+ * @slot before - for content before the greeting
10
+ * @slot after - for content after the greeting and the unnamed slot
11
+ * @cssprop [--border-color=gray] color of border that surrounds the component
12
+ * @csspart greeting - greeting message
13
+ */
14
+ class HelloWrec extends Wrec {
15
+ static properties = {
16
+ color: { doc: "text color", type: String, value: "black" },
17
+ name: { doc: "name to greet", type: String, value: "World" },
18
+ };
19
+
20
+ static css = css`
21
+ :host {
22
+ display: inline-block;
23
+ border: 3px solid var(--border-color, gray);
24
+ margin: 0.5rem 0;
25
+ padding: 0.5rem;
26
+ }
27
+ p {
28
+ color: this.color;
29
+ }
30
+ `;
31
+
32
+ static html = html`
33
+ <slot name="before"></slot>
34
+ <p>Hello, <span>this.name</span>!</p>
35
+ <slot></slot>
36
+ <slot name="after"></slot>
37
+ `;
38
+ }
39
+
40
+ HelloWrec.register();
@@ -0,0 +1,37 @@
1
+ import { css, html, Wrec } from "wrec";
2
+
3
+ /**
4
+ * This is a counter web component implemented with wrec.
5
+ */
6
+ class CounterWrec extends Wrec {
7
+ static properties = {
8
+ count: { doc: "initial value", type: Number, value: 0 },
9
+ };
10
+
11
+ static css = css`
12
+ :host {
13
+ display: flex;
14
+ align-items: center;
15
+ gap: 0.5rem;
16
+ }
17
+
18
+ button {
19
+ background-color: lightgreen;
20
+ }
21
+
22
+ button:disabled {
23
+ opacity: 0.8;
24
+ }
25
+ `;
26
+
27
+ static html = html`
28
+ <button onClick="this.count--" type="button" disabled="this.count === 0">
29
+ -
30
+ </button>
31
+ <span>this.count</span>
32
+ <button onClick="this.count++" type="button">+</button>
33
+ <span>this.count < 10 ? "single" : "double"</span>-digit
34
+ `;
35
+ }
36
+
37
+ CounterWrec.register();
package/index.js CHANGED
@@ -1,4 +1,3 @@
1
- //TODO: Does this support JSDoc comment attributes like @attr by default?
2
1
  export default function wrecPlugin() {
3
2
  const MEMBERS_TO_HIDE = new Set(["css", "html", "properties"]);
4
3
 
@@ -88,13 +87,45 @@ export default function wrecPlugin() {
88
87
  }
89
88
  }
90
89
 
91
- currentClass.attributes.push({
92
- default: value,
93
- description: doc,
94
- fieldName: name,
95
- name,
96
- type,
97
- });
90
+ if (["String", "Number", "Boolean"].includes(type)) {
91
+ type = type.toLowerCase();
92
+ }
93
+
94
+ const attribute = currentClass.attributes.find(
95
+ (obj) => obj.name === name,
96
+ );
97
+ if (attribute) {
98
+ attribute.default = value;
99
+ attribute.description = doc;
100
+ } else {
101
+ currentClass.attributes.push({
102
+ name,
103
+ type: { text: type },
104
+ fieldName: name,
105
+ default: value,
106
+ description: doc,
107
+ });
108
+ }
109
+
110
+ const member = currentClass.members.find(
111
+ (obj) => obj.name === name,
112
+ );
113
+ if (member) {
114
+ member.default = value;
115
+ member.description = doc;
116
+ member.reflects = true;
117
+ } else {
118
+ currentClass.members.push({
119
+ kind: "field",
120
+ name,
121
+ privacy: "public",
122
+ type: { text: type },
123
+ attribute: name,
124
+ default: value,
125
+ description: doc,
126
+ reflects: true,
127
+ });
128
+ }
98
129
  }
99
130
 
100
131
  isStatic = false;
package/package.json CHANGED
@@ -5,16 +5,15 @@
5
5
  "license": "MIT",
6
6
  "main": "index.js",
7
7
  "type": "module",
8
- "version": "0.2.0",
8
+ "version": "0.2.2",
9
9
  "scripts": {
10
+ "cem": "cem analyze",
10
11
  "reinstall": "rm -rf node_modules package-lock.json && npm install",
11
12
  "test": "uvu test"
12
13
  },
13
14
  "devDependencies": {
14
15
  "@custom-elements-manifest/analyzer": "^0.11.0",
15
- "globby": "^16.1.0",
16
- "nodemon": "^3.1.11",
17
- "typescript": "^5.9.3",
18
16
  "uvu": "^0.5.6"
19
- }
17
+ },
18
+ "customElements": "custom-elements.json"
20
19
  }
@@ -1,38 +1,23 @@
1
1
  // This uses the uvu test runner at https://github.com/lukeed/uvu.
2
+ import { execSync } from "child_process";
3
+ import { readFileSync } from "fs";
2
4
  import { test } from "uvu";
3
5
  import * as assert from "uvu/assert";
4
- import path from "path";
5
- import fs from "fs";
6
- import { globby } from "globby";
7
- import ts from "typescript";
8
6
 
9
- import { create } from "@custom-elements-manifest/analyzer/src/create.js";
10
- import myPlugin from "../index.js";
11
-
12
- const fixturesDir = path.join(process.cwd(), "fixtures");
13
- let testCases = fs.readdirSync(fixturesDir);
14
-
15
- testCases.forEach((testCase) => {
16
- test(`Testcase ${testCase}`, async () => {
17
- const fixturePath = path.join(fixturesDir, `${testCase}/expected.json`);
18
- const fixture = JSON.parse(fs.readFileSync(fixturePath, "utf-8"));
19
-
20
- const packagePath = path.join(fixturesDir, `${testCase}/sourcecode`);
21
- const packagePathPosix = packagePath.split(path.sep).join(path.posix.sep);
22
- const outputPath = path.join(fixturesDir, `${testCase}/actual.json`);
23
-
24
- const globs = await globby(packagePathPosix);
25
- const modules = globs.map((glob) => {
26
- const relativeModulePath = `.${path.sep}${path.relative(process.cwd(), glob)}`;
27
- const file = path.basename(relativeModulePath);
28
- const source = fs.readFileSync(relativeModulePath).toString();
29
- return ts.createSourceFile(file, source, ts.ScriptTarget.ES2015, true);
30
- });
31
-
32
- const result = create({ modules, plugins: [myPlugin()] });
33
- fs.writeFileSync(outputPath, JSON.stringify(result, null, 2));
34
- assert.equal(result, fixture);
35
- });
7
+ test("CEM generation", () => {
8
+ // .toString() is needed because execSync returns a Buffer.
9
+ const output = execSync("cem analyze").toString();
10
+ assert.ok(
11
+ output.includes("@custom-elements-manifest/analyzer: Created new manifest"),
12
+ );
13
+ const cem = "custom-elements.json";
14
+ const actual = readFileSync(cem, "utf-8");
15
+ const expected = readFileSync(`./fixtures/expected-${cem}`, "utf-8");
16
+ assert.is(
17
+ actual,
18
+ expected,
19
+ `generated ${cem} does not have expected contents`,
20
+ );
36
21
  });
37
22
 
38
23
  test.run();
@@ -1,61 +0,0 @@
1
- {
2
- "schemaVersion": "1.0.0",
3
- "readme": "",
4
- "modules": [
5
- {
6
- "kind": "javascript-module",
7
- "path": "hello-world.js",
8
- "declarations": [
9
- {
10
- "kind": "class",
11
- "description": "",
12
- "name": "HelloWorld",
13
- "members": [
14
- {
15
- "kind": "field",
16
- "name": "#name",
17
- "privacy": "private",
18
- "type": {
19
- "text": "string"
20
- },
21
- "default": "\"World\""
22
- },
23
- {
24
- "kind": "field",
25
- "name": "#p",
26
- "privacy": "private"
27
- }
28
- ],
29
- "attributes": [
30
- {
31
- "name": "name"
32
- }
33
- ],
34
- "superclass": {
35
- "name": "HTMLElement"
36
- },
37
- "tagName": "hello-world",
38
- "customElement": true
39
- }
40
- ],
41
- "exports": [
42
- {
43
- "kind": "js",
44
- "name": "HelloWorld",
45
- "declaration": {
46
- "name": "HelloWorld",
47
- "module": "hello-world.js"
48
- }
49
- },
50
- {
51
- "kind": "custom-element-definition",
52
- "name": "hello-world",
53
- "declaration": {
54
- "name": "HelloWorld",
55
- "module": "hello-world.js"
56
- }
57
- }
58
- ]
59
- }
60
- ]
61
- }
@@ -1,61 +0,0 @@
1
- {
2
- "schemaVersion": "1.0.0",
3
- "readme": "",
4
- "modules": [
5
- {
6
- "kind": "javascript-module",
7
- "path": "hello-world.js",
8
- "declarations": [
9
- {
10
- "kind": "class",
11
- "description": "",
12
- "name": "HelloWorld",
13
- "members": [
14
- {
15
- "kind": "field",
16
- "name": "#name",
17
- "privacy": "private",
18
- "type": {
19
- "text": "string"
20
- },
21
- "default": "\"World\""
22
- },
23
- {
24
- "kind": "field",
25
- "name": "#p",
26
- "privacy": "private"
27
- }
28
- ],
29
- "attributes": [
30
- {
31
- "name": "name"
32
- }
33
- ],
34
- "superclass": {
35
- "name": "HTMLElement"
36
- },
37
- "tagName": "hello-world",
38
- "customElement": true
39
- }
40
- ],
41
- "exports": [
42
- {
43
- "kind": "js",
44
- "name": "HelloWorld",
45
- "declaration": {
46
- "name": "HelloWorld",
47
- "module": "hello-world.js"
48
- }
49
- },
50
- {
51
- "kind": "custom-element-definition",
52
- "name": "hello-world",
53
- "declaration": {
54
- "name": "HelloWorld",
55
- "module": "hello-world.js"
56
- }
57
- }
58
- ]
59
- }
60
- ]
61
- }
@@ -1,28 +0,0 @@
1
- export class HelloWorld extends HTMLElement {
2
- static get observedAttributes() {
3
- return ["name"];
4
- }
5
-
6
- #name = "World";
7
- #p = document.createElement("p");
8
-
9
- constructor() {
10
- super();
11
- this.attachShadow({ mode: "open" });
12
- }
13
-
14
- connectedCallback() {
15
- this.#p.textContent = `Hello, ${this.#name}!`;
16
- this.shadowRoot.replaceChild(this.#p);
17
- }
18
-
19
- attributeChangedCallback(name, oldValue, newValue) {
20
- console.log("attributeChangedCallback", name, oldValue, newValue);
21
- if (name === "name") {
22
- this.#name = newValue;
23
- this.#p.textContent = `Hello, ${this.#name}!`;
24
- }
25
- }
26
- }
27
-
28
- customElements.define("hello-world", HelloWorld);
@@ -1,12 +0,0 @@
1
- {
2
- "schemaVersion": "1.0.0",
3
- "readme": "",
4
- "modules": [
5
- {
6
- "kind": "javascript-module",
7
- "path": "my-counter.js",
8
- "declarations": [],
9
- "exports": []
10
- }
11
- ]
12
- }
@@ -1,38 +0,0 @@
1
- {
2
- "schemaVersion": "0.1.0",
3
- "readme": "",
4
- "modules": [
5
- {
6
- "kind": "javascript-module",
7
- "path": "my-counter.js",
8
- "declarations": [
9
- {
10
- "kind": "class",
11
- "description": "",
12
- "name": "MyCounter",
13
- "members": [
14
- {
15
- "kind": "field",
16
- "name": "count",
17
- "default": "0"
18
- }
19
- ],
20
- "superclass": {
21
- "name": "Wrec"
22
- },
23
- "customElement": true
24
- }
25
- ],
26
- "exports": [
27
- {
28
- "kind": "js",
29
- "name": "MyCounter",
30
- "declaration": {
31
- "name": "MyCounter",
32
- "module": "my-counter.js"
33
- }
34
- }
35
- ]
36
- }
37
- ]
38
- }
@@ -1,43 +0,0 @@
1
- import { css, html, Wrec } from "wrec";
2
-
3
- /**
4
- * This is a counter web component implemented with wrec.
5
- */
6
- class MyCounter extends Wrec {
7
- static properties = {
8
- count: { doc: "initial value", type: Number, reflect: true, value: 0 },
9
- };
10
-
11
- static css = css`
12
- .counter {
13
- display: flex;
14
- align-items: center;
15
- gap: 0.5rem;
16
- }
17
-
18
- button {
19
- background-color: lightgreen;
20
- }
21
-
22
- button:disabled {
23
- background-color: gray;
24
- }
25
- `;
26
-
27
- static html = html`
28
- <div>
29
- <button onClick="decrement" type="button" disabled="this.count === 0">
30
- -
31
- </button>
32
- <span>this.count</span>
33
- <button onClick="this.count++" type="button">+</button>
34
- <span>(this.count < 10 ? "single" : "double") + " digit"</span>
35
- </div>
36
- `;
37
-
38
- decrement() {
39
- if (this.count > 0) this.count--;
40
- }
41
- }
42
-
43
- MyCounter.register();