@twin.org/nameof-transformer 0.0.2-next.15 → 0.0.2-next.17

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.
@@ -23,6 +23,52 @@ function _interopNamespaceDefault(e) {
23
23
 
24
24
  var ts__namespace = /*#__PURE__*/_interopNamespaceDefault(ts);
25
25
 
26
+ // Copyright 2024 IOTA Stiftung.
27
+ // SPDX-License-Identifier: Apache-2.0.
28
+ /**
29
+ * Camel case all the words.
30
+ * @param input The input to convert.
31
+ * @returns The camel case version of the input.
32
+ */
33
+ function camelCase(input) {
34
+ let output = input;
35
+ // Strip interface prefix if there is one.
36
+ if (/I[A-Z]/.test(output)) {
37
+ output = output.slice(1);
38
+ }
39
+ const words = wordsSplit(output);
40
+ return words.length === 0
41
+ ? ""
42
+ : `${words[0].toLowerCase()}${words
43
+ .slice(1)
44
+ .map(w => `${w[0].toUpperCase()}${w.slice(1).toLowerCase()}`)
45
+ .join("")}`;
46
+ }
47
+ /**
48
+ * Convert the input string to kebab case.
49
+ * @param input The input to convert.
50
+ * @returns The kebab case version of the input.
51
+ */
52
+ function kebabCase(input) {
53
+ let output = input;
54
+ // Strip interface prefix if there is one.
55
+ if (/I[A-Z]/.test(output)) {
56
+ output = output.slice(1);
57
+ }
58
+ return wordsSplit(output).join("-").toLowerCase();
59
+ }
60
+ /**
61
+ * Split a string into words.
62
+ * @param input The input to split.
63
+ * @returns The string split into words.
64
+ */
65
+ function wordsSplit(input) {
66
+ return (input
67
+ .replace(/([A-Z])/g, " $1")
68
+ .trim()
69
+ .match(/[^\u0000-\u002F\u003A-\u0040\u005B-\u0060\u007B-\u007F]+/g) ?? []);
70
+ }
71
+
26
72
  // Copyright 2024 IOTA Stiftung.
27
73
  // SPDX-License-Identifier: Apache-2.0.
28
74
  /**
@@ -70,7 +116,11 @@ function visitNode(node) {
70
116
  }
71
117
  catch { }
72
118
  // Is this a call to nameof<Type>(), if so just replace with a string e.g. "Type"
73
- if (expressionText === "nameof" && node.typeArguments && node.typeArguments.length === 1) {
119
+ if ((expressionText === "nameof" ||
120
+ expressionText === "nameofKebabCase" ||
121
+ expressionText === "nameofCamelCase") &&
122
+ node.typeArguments &&
123
+ node.typeArguments.length === 1) {
74
124
  let typeName;
75
125
  if (ts__namespace.isTypeReferenceNode(node.typeArguments[0])) {
76
126
  typeName = node.typeArguments[0].typeName.getText();
@@ -79,10 +129,20 @@ function visitNode(node) {
79
129
  typeName = `${node.typeArguments[0].elementType.getText()}[]`;
80
130
  }
81
131
  if (typeName) {
132
+ if (expressionText.endsWith("KebabCase")) {
133
+ return ts__namespace.factory.createStringLiteral(kebabCase(typeName));
134
+ }
135
+ else if (expressionText.endsWith("CamelCase")) {
136
+ return ts__namespace.factory.createStringLiteral(camelCase(typeName));
137
+ }
82
138
  return ts__namespace.factory.createStringLiteral(typeName);
83
139
  }
84
140
  }
85
- else if (expressionText === "nameof" && node.arguments && node.arguments.length >= 1) {
141
+ else if ((expressionText === "nameof" ||
142
+ expressionText === "nameofKebabCase" ||
143
+ expressionText === "nameofCamelCase") &&
144
+ node.arguments &&
145
+ node.arguments.length >= 1) {
86
146
  // This is an nameof(propName, ?optionalParent) call.
87
147
  // Return the whole property path as the string, but remove any chaining operators
88
148
  // The second parameter is an optional string, if set change the top level owner
@@ -95,6 +155,12 @@ function visitNode(node) {
95
155
  return ts__namespace.factory.createBinaryExpression(ts__namespace.factory.createIdentifier(node.arguments[1].getText()), ts__namespace.factory.createToken(ts__namespace.SyntaxKind.PlusToken), ts__namespace.factory.createStringLiteral(parts.join(".")));
96
156
  }
97
157
  }
158
+ if (expressionText.endsWith("KebabCase")) {
159
+ return ts__namespace.factory.createStringLiteral(kebabCase(propertyPath));
160
+ }
161
+ else if (expressionText.endsWith("CamelCase")) {
162
+ return ts__namespace.factory.createStringLiteral(camelCase(propertyPath));
163
+ }
98
164
  return ts__namespace.factory.createStringLiteral(propertyPath);
99
165
  }
100
166
  }
@@ -123,9 +189,25 @@ function manual(content) {
123
189
  // or the nameof<IMyObject<IType2>>() with "IMyObject"
124
190
  const nameRegEx = /nameof<(.*?)(?:<.*>)?>\(\)/g;
125
191
  content = content.replace(nameRegEx, '"$1"');
192
+ // Replace the nameofCamelCase<IMyObject>() with the camelCase version of the type name
193
+ // e.g. nameofCamelCase<IMyObject>() => "myObject"
194
+ // and nameofCamelCase<IMyObject<IType2>>() => "myObject"
195
+ const nameRegExCamelCase = /nameofCamelCase<(.*?)(?:<.*?>)?>\(\)/g;
196
+ content = content.replace(nameRegExCamelCase, (_match, typeName) => `"${camelCase(typeName)}"`);
197
+ // Replace the nameofKebabCase<IMyObject>() with the kebabCase version of the type name
198
+ // e.g. nameofKebabCase<IMyObject>() => "my-object"
199
+ // and nameofKebabCase<IMyObject<IType2>>() => "my-object"
200
+ const nameRegExKebabCase = /nameofKebabCase<(.*?)(?:<.*?>)?>\(\)/g;
201
+ content = content.replace(nameRegExKebabCase, (_match, typeName) => `"${kebabCase(typeName)}"`);
126
202
  // Replace the nameof(object?.prop) with "object.prop"
127
203
  const propRegEx = /nameof\((.*?)\)/g;
128
204
  content = content.replace(propRegEx, '"$1"');
205
+ // Replace the nameofCamelCase(object?.prop) with "object.prop"
206
+ const propRegExCamelCase = /nameofCamelCase\((.*?)\)/g;
207
+ content = content.replace(propRegExCamelCase, (_match, typeName) => `"${camelCase(typeName)}"`);
208
+ // Replace the nameofKebabCase(object?.prop) with "object.prop"
209
+ const propRegExKebabCase = /nameofKebabCase\((.*?)\)/g;
210
+ content = content.replace(propRegExKebabCase, (_match, typeName) => `"${kebabCase(typeName)}"`);
129
211
  }
130
212
  return content;
131
213
  }
@@ -162,7 +244,7 @@ const factory = () => transformerFactory;
162
244
  * Exports the factory version.
163
245
  * @returns The factory.
164
246
  */
165
- const version = "0.0.2-next.15"; // x-release-please-version
247
+ const version = "0.0.2-next.17"; // x-release-please-version
166
248
  /**
167
249
  * Exports the factory name.
168
250
  * @returns The factory.
@@ -1,5 +1,51 @@
1
1
  import * as ts from 'typescript';
2
2
 
3
+ // Copyright 2024 IOTA Stiftung.
4
+ // SPDX-License-Identifier: Apache-2.0.
5
+ /**
6
+ * Camel case all the words.
7
+ * @param input The input to convert.
8
+ * @returns The camel case version of the input.
9
+ */
10
+ function camelCase(input) {
11
+ let output = input;
12
+ // Strip interface prefix if there is one.
13
+ if (/I[A-Z]/.test(output)) {
14
+ output = output.slice(1);
15
+ }
16
+ const words = wordsSplit(output);
17
+ return words.length === 0
18
+ ? ""
19
+ : `${words[0].toLowerCase()}${words
20
+ .slice(1)
21
+ .map(w => `${w[0].toUpperCase()}${w.slice(1).toLowerCase()}`)
22
+ .join("")}`;
23
+ }
24
+ /**
25
+ * Convert the input string to kebab case.
26
+ * @param input The input to convert.
27
+ * @returns The kebab case version of the input.
28
+ */
29
+ function kebabCase(input) {
30
+ let output = input;
31
+ // Strip interface prefix if there is one.
32
+ if (/I[A-Z]/.test(output)) {
33
+ output = output.slice(1);
34
+ }
35
+ return wordsSplit(output).join("-").toLowerCase();
36
+ }
37
+ /**
38
+ * Split a string into words.
39
+ * @param input The input to split.
40
+ * @returns The string split into words.
41
+ */
42
+ function wordsSplit(input) {
43
+ return (input
44
+ .replace(/([A-Z])/g, " $1")
45
+ .trim()
46
+ .match(/[^\u0000-\u002F\u003A-\u0040\u005B-\u0060\u007B-\u007F]+/g) ?? []);
47
+ }
48
+
3
49
  // Copyright 2024 IOTA Stiftung.
4
50
  // SPDX-License-Identifier: Apache-2.0.
5
51
  /**
@@ -47,7 +93,11 @@ function visitNode(node) {
47
93
  }
48
94
  catch { }
49
95
  // Is this a call to nameof<Type>(), if so just replace with a string e.g. "Type"
50
- if (expressionText === "nameof" && node.typeArguments && node.typeArguments.length === 1) {
96
+ if ((expressionText === "nameof" ||
97
+ expressionText === "nameofKebabCase" ||
98
+ expressionText === "nameofCamelCase") &&
99
+ node.typeArguments &&
100
+ node.typeArguments.length === 1) {
51
101
  let typeName;
52
102
  if (ts.isTypeReferenceNode(node.typeArguments[0])) {
53
103
  typeName = node.typeArguments[0].typeName.getText();
@@ -56,10 +106,20 @@ function visitNode(node) {
56
106
  typeName = `${node.typeArguments[0].elementType.getText()}[]`;
57
107
  }
58
108
  if (typeName) {
109
+ if (expressionText.endsWith("KebabCase")) {
110
+ return ts.factory.createStringLiteral(kebabCase(typeName));
111
+ }
112
+ else if (expressionText.endsWith("CamelCase")) {
113
+ return ts.factory.createStringLiteral(camelCase(typeName));
114
+ }
59
115
  return ts.factory.createStringLiteral(typeName);
60
116
  }
61
117
  }
62
- else if (expressionText === "nameof" && node.arguments && node.arguments.length >= 1) {
118
+ else if ((expressionText === "nameof" ||
119
+ expressionText === "nameofKebabCase" ||
120
+ expressionText === "nameofCamelCase") &&
121
+ node.arguments &&
122
+ node.arguments.length >= 1) {
63
123
  // This is an nameof(propName, ?optionalParent) call.
64
124
  // Return the whole property path as the string, but remove any chaining operators
65
125
  // The second parameter is an optional string, if set change the top level owner
@@ -72,6 +132,12 @@ function visitNode(node) {
72
132
  return ts.factory.createBinaryExpression(ts.factory.createIdentifier(node.arguments[1].getText()), ts.factory.createToken(ts.SyntaxKind.PlusToken), ts.factory.createStringLiteral(parts.join(".")));
73
133
  }
74
134
  }
135
+ if (expressionText.endsWith("KebabCase")) {
136
+ return ts.factory.createStringLiteral(kebabCase(propertyPath));
137
+ }
138
+ else if (expressionText.endsWith("CamelCase")) {
139
+ return ts.factory.createStringLiteral(camelCase(propertyPath));
140
+ }
75
141
  return ts.factory.createStringLiteral(propertyPath);
76
142
  }
77
143
  }
@@ -100,9 +166,25 @@ function manual(content) {
100
166
  // or the nameof<IMyObject<IType2>>() with "IMyObject"
101
167
  const nameRegEx = /nameof<(.*?)(?:<.*>)?>\(\)/g;
102
168
  content = content.replace(nameRegEx, '"$1"');
169
+ // Replace the nameofCamelCase<IMyObject>() with the camelCase version of the type name
170
+ // e.g. nameofCamelCase<IMyObject>() => "myObject"
171
+ // and nameofCamelCase<IMyObject<IType2>>() => "myObject"
172
+ const nameRegExCamelCase = /nameofCamelCase<(.*?)(?:<.*?>)?>\(\)/g;
173
+ content = content.replace(nameRegExCamelCase, (_match, typeName) => `"${camelCase(typeName)}"`);
174
+ // Replace the nameofKebabCase<IMyObject>() with the kebabCase version of the type name
175
+ // e.g. nameofKebabCase<IMyObject>() => "my-object"
176
+ // and nameofKebabCase<IMyObject<IType2>>() => "my-object"
177
+ const nameRegExKebabCase = /nameofKebabCase<(.*?)(?:<.*?>)?>\(\)/g;
178
+ content = content.replace(nameRegExKebabCase, (_match, typeName) => `"${kebabCase(typeName)}"`);
103
179
  // Replace the nameof(object?.prop) with "object.prop"
104
180
  const propRegEx = /nameof\((.*?)\)/g;
105
181
  content = content.replace(propRegEx, '"$1"');
182
+ // Replace the nameofCamelCase(object?.prop) with "object.prop"
183
+ const propRegExCamelCase = /nameofCamelCase\((.*?)\)/g;
184
+ content = content.replace(propRegExCamelCase, (_match, typeName) => `"${camelCase(typeName)}"`);
185
+ // Replace the nameofKebabCase(object?.prop) with "object.prop"
186
+ const propRegExKebabCase = /nameofKebabCase\((.*?)\)/g;
187
+ content = content.replace(propRegExKebabCase, (_match, typeName) => `"${kebabCase(typeName)}"`);
106
188
  }
107
189
  return content;
108
190
  }
@@ -139,7 +221,7 @@ const factory = () => transformerFactory;
139
221
  * Exports the factory version.
140
222
  * @returns The factory.
141
223
  */
142
- const version = "0.0.2-next.15"; // x-release-please-version
224
+ const version = "0.0.2-next.17"; // x-release-please-version
143
225
  /**
144
226
  * Exports the factory name.
145
227
  * @returns The factory.
@@ -8,7 +8,7 @@ export declare const factory: () => ts.TransformerFactory<ts.Node>;
8
8
  * Exports the factory version.
9
9
  * @returns The factory.
10
10
  */
11
- export declare const version = "0.0.2-next.15";
11
+ export declare const version = "0.0.2-next.17";
12
12
  /**
13
13
  * Exports the factory name.
14
14
  * @returns The factory.
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Camel case all the words.
3
+ * @param input The input to convert.
4
+ * @returns The camel case version of the input.
5
+ */
6
+ export declare function camelCase(input: string): string;
7
+ /**
8
+ * Convert the input string to kebab case.
9
+ * @param input The input to convert.
10
+ * @returns The kebab case version of the input.
11
+ */
12
+ export declare function kebabCase(input: string): string;
13
+ /**
14
+ * Split a string into words.
15
+ * @param input The input to split.
16
+ * @returns The string split into words.
17
+ */
18
+ export declare function wordsSplit(input: string): string[];
package/docs/changelog.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @twin.org/nameof-transformer - Changelog
2
2
 
3
+ ## [0.0.2-next.17](https://github.com/twinfoundation/framework/compare/nameof-transformer-v0.0.2-next.16...nameof-transformer-v0.0.2-next.17) (2025-09-29)
4
+
5
+
6
+ ### Features
7
+
8
+ * additional nameof operators ([a5aab60](https://github.com/twinfoundation/framework/commit/a5aab60bf66a86f1b7ff8af7c4f044cb03706d50))
9
+
10
+ ## [0.0.2-next.16](https://github.com/twinfoundation/framework/compare/nameof-transformer-v0.0.2-next.15...nameof-transformer-v0.0.2-next.16) (2025-09-28)
11
+
12
+
13
+ ### Features
14
+
15
+ * nodeIdentity optional in IComponent methods ([c78dc17](https://github.com/twinfoundation/framework/commit/c78dc17f4357d3e1ae40e415f468d3eae13e81f4))
16
+
3
17
  ## [0.0.2-next.15](https://github.com/twinfoundation/framework/compare/nameof-transformer-v0.0.2-next.14...nameof-transformer-v0.0.2-next.15) (2025-09-22)
4
18
 
5
19
 
@@ -1,6 +1,6 @@
1
1
  # Variable: version
2
2
 
3
- > `const` **version**: `"0.0.2-next.15"` = `"0.0.2-next.15"`
3
+ > `const` **version**: `"0.0.2-next.17"` = `"0.0.2-next.17"`
4
4
 
5
5
  Exports the factory version.
6
6
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twin.org/nameof-transformer",
3
- "version": "0.0.2-next.15",
3
+ "version": "0.0.2-next.17",
4
4
  "description": "A TypeScript transformer which converts types and properties to their actual name for use at runtime",
5
5
  "repository": {
6
6
  "type": "git",