@elenajs/plugin-cem-define 0.3.0 → 1.0.0-beta.1

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.
Files changed (3) hide show
  1. package/README.md +8 -20
  2. package/package.json +10 -2
  3. package/src/index.js +40 -72
package/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  <div align="center">
2
2
  <picture>
3
- <source media="(prefers-color-scheme: dark)" srcset="https://elenajs.com/img/elena-dark.png" alt="Elena" width="201" height="230">
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://elenajs.com/img/elena-dark.png" alt="Elena" width="558" height="220">
4
4
  </source>
5
- <source media="(prefers-color-scheme: light)" srcset="https://elenajs.com/img/elena.png" alt="Elena" width="201" height="230">
5
+ <source media="(prefers-color-scheme: light)" srcset="https://elenajs.com/img/elena-light.png" alt="Elena" width="558" height="220">
6
6
  </source>
7
- <img src="https://elenajs.com/img/elena.png" alt="Elena" width="201" height="230">
7
+ <img src="https://elenajs.com/img/elena-light.png" alt="Elena" width="558" height="220">
8
8
  </picture>
9
9
 
10
10
  ### CEM analyzer plugin that registers the Elena components in the manifest.
@@ -66,27 +66,15 @@ export default {
66
66
 
67
67
  ## How it works
68
68
 
69
- The plugin scans Elena component source files and extracts the `tagName` from the options object passed to `Elena()`. It supports two patterns:
70
-
71
- **Inline options:**
69
+ The plugin scans Elena component source files and extracts the value of the `static tagName` class field:
72
70
 
73
71
  ```js
74
- class Button extends Elena(HTMLElement, {
75
- tagName: "elena-button",
76
- }) {}
77
- ```
78
-
79
- **Variable reference:**
80
-
81
- ```js
82
- const options = {
83
- tagName: "elena-button",
84
- };
85
-
86
- class Button extends Elena(HTMLElement, options) {}
72
+ class Button extends Elena(HTMLElement) {
73
+ static tagName = "elena-button";
74
+ }
87
75
  ```
88
76
 
89
- In both cases, the plugin adds the `tagName` to the CEM class declaration and creates a `custom-element-definition` export entry, making the component discoverable by IDEs and documentation tools.
77
+ It adds the `tagName` to the CEM class declaration and creates a `custom-element-definition` export entry, making the component discoverable by IDEs and documentation tools.
90
78
 
91
79
  ## License
92
80
 
package/package.json CHANGED
@@ -1,9 +1,17 @@
1
1
  {
2
2
  "name": "@elenajs/plugin-cem-define",
3
- "version": "0.3.0",
3
+ "version": "1.0.0-beta.1",
4
4
  "description": "CEM analyzer plugin that registers the Elena components in the manifest.",
5
5
  "author": "Elena <hi@elenajs.com>",
6
6
  "homepage": "https://elenajs.com/",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/getelena/elena.git",
10
+ "directory": "packages/plugin-cem-define"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/getelena/elena/issues"
14
+ },
7
15
  "license": "MIT",
8
16
  "publishConfig": {
9
17
  "access": "public"
@@ -28,5 +36,5 @@
28
36
  "@custom-elements-manifest/analyzer": "0.11.0",
29
37
  "vitest": "4.0.18"
30
38
  },
31
- "gitHead": "c181af0625f691a95a5cb1ef9adb0d7f2c796eae"
39
+ "gitHead": "66d1e66dd467c20d7c5c70ffcb5678c6a2694690"
32
40
  }
package/src/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * ██████████ ████
3
3
  * ░░███░░░░░█░░███
4
- * ░███ █ ░ ███ ██████ ████████ ██████
5
- * ░██████ ███ ███░░███░░███░░███ ░░░░░███
6
- * ░███░░█ ███ ░███████ ░███ ░███ ███████
7
- * ░███ ░ █ ███ ░███░░░ ░███ ░███ ███░░███
4
+ * ░███ █ ░ ░███ ██████ ████████ ██████
5
+ * ░██████ ░███ ███░░███░░███░░███ ░░░░░███
6
+ * ░███░░█ ░███ ░███████ ░███ ░███ ███████
7
+ * ░███ ░ █ ░███ ░███░░░ ░███ ░███ ███░░███
8
8
  * ██████████ █████░░██████ ████ █████░░████████
9
9
  * ░░░░░░░░░░ ░░░░░ ░░░░░░ ░░░░ ░░░░░ ░░░░░░░░
10
10
  *
@@ -13,37 +13,16 @@
13
13
  */
14
14
 
15
15
  /**
16
- * CEM analyzer plugin that reads `tagName` from the options object passed to
17
- * `Elena(superClass, { tagName: "...", ... })` and registers the element in the manifest.
18
- *
19
- * Supports both inline objects and variable references:
20
- * - `Elena(HTMLElement, { tagName: "elena-button", ... })`
21
- * - `const options = { tagName: "elena-button", ... }; Elena(HTMLElement, options)`
16
+ * CEM analyzer plugin that reads `static tagName` from an Elena component class
17
+ * and registers the element in the manifest.
22
18
  *
23
19
  * @returns {import("@custom-elements-manifest/analyzer").Plugin}
24
20
  */
25
21
  export function elenaDefinePlugin() {
26
- /** @type {Map<string, string>} variable name → tag name */
27
- const optionsMap = new Map();
28
-
29
22
  return {
30
23
  name: "define-element",
31
24
 
32
25
  analyzePhase({ ts, node, moduleDoc }) {
33
- // Collect variable declarations: const options = { tagName: "...", ... }
34
- if (
35
- ts.isVariableDeclaration(node) &&
36
- node.initializer &&
37
- ts.isObjectLiteralExpression(node.initializer)
38
- ) {
39
- const varName = node.name.getText();
40
- const tagName = getTagName(ts, node.initializer);
41
- if (tagName) {
42
- optionsMap.set(varName, tagName);
43
- }
44
- return;
45
- }
46
-
47
26
  if (!ts.isClassDeclaration(node)) {
48
27
  return;
49
28
  }
@@ -53,65 +32,54 @@ export function elenaDefinePlugin() {
53
32
  return;
54
33
  }
55
34
 
56
- // Skip classes that don't extend anything (no `extends` clause)
35
+ // Skip classes that don't extend Elena(...)
57
36
  const heritageClause = node.heritageClauses?.[0];
58
- if (!heritageClause) {
37
+ if (
38
+ !heritageClause?.types.some(
39
+ t => ts.isCallExpression(t.expression) && t.expression.expression.getText() === "Elena"
40
+ )
41
+ ) {
59
42
  return;
60
43
  }
61
44
 
62
- for (const type of heritageClause.types) {
63
- const expr = type.expression;
64
- if (!ts.isCallExpression(expr) || expr.expression.getText() !== "Elena") {
65
- continue;
66
- }
67
-
68
- const optionsArg = expr.arguments[1];
69
- if (!optionsArg) {
70
- continue;
71
- }
72
-
73
- let tagName;
74
-
75
- if (ts.isObjectLiteralExpression(optionsArg)) {
76
- // Inline: Elena(HTMLElement, { tagName: "...", ... })
77
- tagName = getTagName(ts, optionsArg);
78
- } else if (ts.isIdentifier(optionsArg)) {
79
- // Variable reference: Elena(HTMLElement, options)
80
- tagName = optionsMap.get(optionsArg.getText());
81
- }
82
-
83
- if (!tagName) {
84
- continue;
85
- }
86
-
87
- const declaration = moduleDoc.declarations?.find(d => d.name === className);
88
- if (declaration) {
89
- declaration.tagName = tagName;
90
- }
45
+ const tagName = getStaticTagName(ts, node);
46
+ if (!tagName) {
47
+ return;
48
+ }
91
49
 
92
- moduleDoc.exports ??= [];
93
- moduleDoc.exports.push({
94
- kind: "custom-element-definition",
95
- name: tagName,
96
- declaration: { name: className, module: moduleDoc.path },
97
- });
50
+ const declaration = moduleDoc.declarations?.find(d => d.name === className);
51
+ if (declaration) {
52
+ declaration.tagName = tagName;
98
53
  }
54
+
55
+ moduleDoc.exports ??= [];
56
+ moduleDoc.exports.push({
57
+ kind: "custom-element-definition",
58
+ name: tagName,
59
+ declaration: { name: className, module: moduleDoc.path },
60
+ });
99
61
  },
100
62
  };
101
63
  }
102
64
 
103
65
  /**
104
- * Extracts the `tagName` string value from an object literal expression.
66
+ * Extracts the `tagName` string value from a `static tagName = "..."` class field.
67
+ *
105
68
  * @param {import("typescript")} ts
106
- * @param {import("typescript").ObjectLiteralExpression} objectLiteral
69
+ * @param {import("typescript").ClassDeclaration} classNode
107
70
  * @returns {string | undefined}
108
71
  */
109
- function getTagName(ts, objectLiteral) {
110
- const prop = objectLiteral.properties.find(
111
- p => ts.isPropertyAssignment(p) && p.name.getText() === "tagName"
112
- );
113
- if (prop && ts.isStringLiteral(prop.initializer)) {
114
- return prop.initializer.text;
72
+ function getStaticTagName(ts, classNode) {
73
+ for (const member of classNode.members) {
74
+ if (
75
+ ts.isPropertyDeclaration(member) &&
76
+ member.modifiers?.some(m => m.kind === ts.SyntaxKind.StaticKeyword) &&
77
+ member.name?.getText() === "tagName" &&
78
+ member.initializer &&
79
+ ts.isStringLiteral(member.initializer)
80
+ ) {
81
+ return member.initializer.text;
82
+ }
115
83
  }
116
84
  return undefined;
117
85
  }