@twin.org/nameof-transformer 0.0.2-next.8 → 0.0.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.
package/README.md CHANGED
@@ -1,22 +1,20 @@
1
1
  # TWIN Nameof TypeScript Transformer
2
2
 
3
- This transformer is used to convert class/type/property names to embedded strings, so that they are available to the code at runtime.
4
-
5
- It is used during your TypeScript compilation as part of the build pipeline.
6
-
7
- It is necessary that your code is built with a compiler that supports transformers such as `ts-patch` / `ttypescript` / `ttsc`.
8
-
9
- You will also need to include the `@twin.org/nameof` to be able to reference the methods in your code.
3
+ This package is part of the framework workspace and provides typed transformer which converts types and properties to their actual name for use at runtime to support consistent development workflows across the ecosystem.
10
4
 
11
5
  ## Installation
12
6
 
13
7
  ```shell
14
- npm install @twin.org/nameof-transformer -D
8
+ npm install -D @twin.org/nameof-transformer
15
9
  ```
16
10
 
17
11
  ## Configuration
18
12
 
19
- Configuration of the package is shown in [docs/configuration.md](docs/configuration.md)
13
+ Configuration options are documented in [docs/configuration.md](docs/configuration.md)
14
+
15
+ ## Examples
16
+
17
+ Usage of the APIs is shown in the examples [docs/examples.md](docs/examples.md)
20
18
 
21
19
  ## Reference
22
20
 
@@ -0,0 +1,22 @@
1
+ import { transformerFactory } from "./transformer.js";
2
+ /**
3
+ * Exports the factory.
4
+ * @returns The factory.
5
+ */
6
+ export function factory() {
7
+ return transformerFactory;
8
+ }
9
+ /**
10
+ * Exports the factory version.
11
+ * @returns The factory.
12
+ */
13
+ export const version = "0.0.2"; // x-release-please-version
14
+ /**
15
+ * Exports the factory name.
16
+ * @returns The factory.
17
+ */
18
+ export const name = "@twin.org/nameof-transformer";
19
+ export * from "./manual.js";
20
+ export * from "./svelte.js";
21
+ export default factory;
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEtD;;;GAGG;AACH,MAAM,UAAU,OAAO;IACtB,OAAO,kBAAkB,CAAC;AAC3B,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,2BAA2B;AAE3D;;;GAGG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,8BAA8B,CAAC;AAEnD,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAE5B,eAAe,OAAO,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type * as ts from \"typescript\";\nimport { transformerFactory } from \"./transformer.js\";\n\n/**\n * Exports the factory.\n * @returns The factory.\n */\nexport function factory(): ts.TransformerFactory<ts.Node> {\n\treturn transformerFactory;\n}\n\n/**\n * Exports the factory version.\n * @returns The factory.\n */\nexport const version = \"0.0.2\"; // x-release-please-version\n\n/**\n * Exports the factory name.\n * @returns The factory.\n */\nexport const name = \"@twin.org/nameof-transformer\";\n\nexport * from \"./manual.js\";\nexport * from \"./svelte.js\";\n\nexport default factory;\n"]}
@@ -0,0 +1,39 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ import { camelCase, kebabCase } from "./stringHelper.js";
4
+ /**
5
+ * Replace the transformers manually.
6
+ * @param content The content to replace the transformers in.
7
+ * @returns The content with the transformers replace.
8
+ */
9
+ export function manual(content) {
10
+ if (typeof content === "string" && content.includes("nameof")) {
11
+ // Remove the import
12
+ content = content.replace(/import.*from "@twin\.org\/nameof";/g, "");
13
+ // Replace the nameof<IMyObject>() with "IMyObject"
14
+ // or the nameof<IMyObject<IType2>>() with "IMyObject"
15
+ const nameRegEx = /nameof<(.*?)(?:<.*>)?>\(\)/g;
16
+ content = content.replace(nameRegEx, '"$1"');
17
+ // Replace the nameofCamelCase<IMyObject>() with the camelCase version of the type name
18
+ // e.g. nameofCamelCase<IMyObject>() => "myObject"
19
+ // and nameofCamelCase<IMyObject<IType2>>() => "myObject"
20
+ const nameRegExCamelCase = /nameofCamelCase<(.*?)(?:<.*?>)?>\(\)/g;
21
+ content = content.replace(nameRegExCamelCase, (_match, typeName) => `"${camelCase(typeName)}"`);
22
+ // Replace the nameofKebabCase<IMyObject>() with the kebabCase version of the type name
23
+ // e.g. nameofKebabCase<IMyObject>() => "my-object"
24
+ // and nameofKebabCase<IMyObject<IType2>>() => "my-object"
25
+ const nameRegExKebabCase = /nameofKebabCase<(.*?)(?:<.*?>)?>\(\)/g;
26
+ content = content.replace(nameRegExKebabCase, (_match, typeName) => `"${kebabCase(typeName)}"`);
27
+ // Replace the nameof(object?.prop) with "object.prop"
28
+ const propRegEx = /nameof\((.*?)\)/g;
29
+ content = content.replace(propRegEx, '"$1"');
30
+ // Replace the nameofCamelCase(object?.prop) with "object.prop"
31
+ const propRegExCamelCase = /nameofCamelCase\((.*?)\)/g;
32
+ content = content.replace(propRegExCamelCase, (_match, typeName) => `"${camelCase(typeName)}"`);
33
+ // Replace the nameofKebabCase(object?.prop) with "object.prop"
34
+ const propRegExKebabCase = /nameofKebabCase\((.*?)\)/g;
35
+ content = content.replace(propRegExKebabCase, (_match, typeName) => `"${kebabCase(typeName)}"`);
36
+ }
37
+ return content;
38
+ }
39
+ //# sourceMappingURL=manual.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manual.js","sourceRoot":"","sources":["../../src/manual.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEzD;;;;GAIG;AACH,MAAM,UAAU,MAAM,CAAC,OAAe;IACrC,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/D,oBAAoB;QACpB,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,qCAAqC,EAAE,EAAE,CAAC,CAAC;QAErE,mDAAmD;QACnD,sDAAsD;QACtD,MAAM,SAAS,GAAG,6BAA6B,CAAC;QAChD,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QAE7C,uFAAuF;QACvF,kDAAkD;QAClD,yDAAyD;QACzD,MAAM,kBAAkB,GAAG,uCAAuC,CAAC;QACnE,OAAO,GAAG,OAAO,CAAC,OAAO,CACxB,kBAAkB,EAClB,CAAC,MAAM,EAAE,QAAgB,EAAE,EAAE,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,GAAG,CACxD,CAAC;QAEF,uFAAuF;QACvF,mDAAmD;QACnD,0DAA0D;QAC1D,MAAM,kBAAkB,GAAG,uCAAuC,CAAC;QACnE,OAAO,GAAG,OAAO,CAAC,OAAO,CACxB,kBAAkB,EAClB,CAAC,MAAM,EAAE,QAAgB,EAAE,EAAE,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,GAAG,CACxD,CAAC;QAEF,sDAAsD;QACtD,MAAM,SAAS,GAAG,kBAAkB,CAAC;QACrC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QAE7C,+DAA+D;QAC/D,MAAM,kBAAkB,GAAG,2BAA2B,CAAC;QACvD,OAAO,GAAG,OAAO,CAAC,OAAO,CACxB,kBAAkB,EAClB,CAAC,MAAM,EAAE,QAAgB,EAAE,EAAE,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,GAAG,CACxD,CAAC;QAEF,+DAA+D;QAC/D,MAAM,kBAAkB,GAAG,2BAA2B,CAAC;QACvD,OAAO,GAAG,OAAO,CAAC,OAAO,CACxB,kBAAkB,EAClB,CAAC,MAAM,EAAE,QAAgB,EAAE,EAAE,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,GAAG,CACxD,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AAChB,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { camelCase, kebabCase } from \"./stringHelper.js\";\n\n/**\n * Replace the transformers manually.\n * @param content The content to replace the transformers in.\n * @returns The content with the transformers replace.\n */\nexport function manual(content: string): string {\n\tif (typeof content === \"string\" && content.includes(\"nameof\")) {\n\t\t// Remove the import\n\t\tcontent = content.replace(/import.*from \"@twin\\.org\\/nameof\";/g, \"\");\n\n\t\t// Replace the nameof<IMyObject>() with \"IMyObject\"\n\t\t// or the nameof<IMyObject<IType2>>() with \"IMyObject\"\n\t\tconst nameRegEx = /nameof<(.*?)(?:<.*>)?>\\(\\)/g;\n\t\tcontent = content.replace(nameRegEx, '\"$1\"');\n\n\t\t// Replace the nameofCamelCase<IMyObject>() with the camelCase version of the type name\n\t\t// e.g. nameofCamelCase<IMyObject>() => \"myObject\"\n\t\t// and nameofCamelCase<IMyObject<IType2>>() => \"myObject\"\n\t\tconst nameRegExCamelCase = /nameofCamelCase<(.*?)(?:<.*?>)?>\\(\\)/g;\n\t\tcontent = content.replace(\n\t\t\tnameRegExCamelCase,\n\t\t\t(_match, typeName: string) => `\"${camelCase(typeName)}\"`\n\t\t);\n\n\t\t// Replace the nameofKebabCase<IMyObject>() with the kebabCase version of the type name\n\t\t// e.g. nameofKebabCase<IMyObject>() => \"my-object\"\n\t\t// and nameofKebabCase<IMyObject<IType2>>() => \"my-object\"\n\t\tconst nameRegExKebabCase = /nameofKebabCase<(.*?)(?:<.*?>)?>\\(\\)/g;\n\t\tcontent = content.replace(\n\t\t\tnameRegExKebabCase,\n\t\t\t(_match, typeName: string) => `\"${kebabCase(typeName)}\"`\n\t\t);\n\n\t\t// Replace the nameof(object?.prop) with \"object.prop\"\n\t\tconst propRegEx = /nameof\\((.*?)\\)/g;\n\t\tcontent = content.replace(propRegEx, '\"$1\"');\n\n\t\t// Replace the nameofCamelCase(object?.prop) with \"object.prop\"\n\t\tconst propRegExCamelCase = /nameofCamelCase\\((.*?)\\)/g;\n\t\tcontent = content.replace(\n\t\t\tpropRegExCamelCase,\n\t\t\t(_match, typeName: string) => `\"${camelCase(typeName)}\"`\n\t\t);\n\n\t\t// Replace the nameofKebabCase(object?.prop) with \"object.prop\"\n\t\tconst propRegExKebabCase = /nameofKebabCase\\((.*?)\\)/g;\n\t\tcontent = content.replace(\n\t\t\tpropRegExKebabCase,\n\t\t\t(_match, typeName: string) => `\"${kebabCase(typeName)}\"`\n\t\t);\n\t}\n\treturn content;\n}\n"]}
@@ -0,0 +1,46 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ /**
4
+ * Camel case all the words.
5
+ * @param input The input to convert.
6
+ * @returns The camel case version of the input.
7
+ */
8
+ export function camelCase(input) {
9
+ let output = input;
10
+ // Strip interface prefix if there is one.
11
+ if (/I[A-Z]/.test(output)) {
12
+ output = output.slice(1);
13
+ }
14
+ const words = wordsSplit(output);
15
+ return words.length === 0
16
+ ? ""
17
+ : `${words[0].toLowerCase()}${words
18
+ .slice(1)
19
+ .map(w => `${w[0].toUpperCase()}${w.slice(1).toLowerCase()}`)
20
+ .join("")}`;
21
+ }
22
+ /**
23
+ * Convert the input string to kebab case.
24
+ * @param input The input to convert.
25
+ * @returns The kebab case version of the input.
26
+ */
27
+ export function kebabCase(input) {
28
+ let output = input;
29
+ // Strip interface prefix if there is one.
30
+ if (/I[A-Z]/.test(output)) {
31
+ output = output.slice(1);
32
+ }
33
+ return wordsSplit(output).join("-").toLowerCase();
34
+ }
35
+ /**
36
+ * Split a string into words.
37
+ * @param input The input to split.
38
+ * @returns The string split into words.
39
+ */
40
+ export function wordsSplit(input) {
41
+ return (input
42
+ .replace(/([A-Z])/g, " $1")
43
+ .trim()
44
+ .match(/[^\u0000-\u002F\u003A-\u0040\u005B-\u0060\u007B-\u007F]+/g) ?? []);
45
+ }
46
+ //# sourceMappingURL=stringHelper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stringHelper.js","sourceRoot":"","sources":["../../src/stringHelper.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AAEvC;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,KAAa;IACtC,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,0CAA0C;IAC1C,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC1B,CAAC;IACD,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IACjC,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;QACxB,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,KAAK;aAChC,KAAK,CAAC,CAAC,CAAC;aACR,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;aAC5D,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,KAAa;IACtC,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,0CAA0C;IAC1C,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;AACnD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,KAAa;IACvC,OAAO,CACN,KAAK;SACH,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC;SAC1B,IAAI,EAAE;SACN,KAAK,CAAC,2DAA2D,CAAC,IAAI,EAAE,CAC1E,CAAC;AACH,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Camel case all the words.\n * @param input The input to convert.\n * @returns The camel case version of the input.\n */\nexport function camelCase(input: string): string {\n\tlet output = input;\n\t// Strip interface prefix if there is one.\n\tif (/I[A-Z]/.test(output)) {\n\t\toutput = output.slice(1);\n\t}\n\tconst words = wordsSplit(output);\n\treturn words.length === 0\n\t\t? \"\"\n\t\t: `${words[0].toLowerCase()}${words\n\t\t\t\t.slice(1)\n\t\t\t\t.map(w => `${w[0].toUpperCase()}${w.slice(1).toLowerCase()}`)\n\t\t\t\t.join(\"\")}`;\n}\n\n/**\n * Convert the input string to kebab case.\n * @param input The input to convert.\n * @returns The kebab case version of the input.\n */\nexport function kebabCase(input: string): string {\n\tlet output = input;\n\t// Strip interface prefix if there is one.\n\tif (/I[A-Z]/.test(output)) {\n\t\toutput = output.slice(1);\n\t}\n\treturn wordsSplit(output).join(\"-\").toLowerCase();\n}\n\n/**\n * Split a string into words.\n * @param input The input to split.\n * @returns The string split into words.\n */\nexport function wordsSplit(input: string): string[] {\n\treturn (\n\t\tinput\n\t\t\t.replace(/([A-Z])/g, \" $1\")\n\t\t\t.trim()\n\t\t\t.match(/[^\\u0000-\\u002F\\u003A-\\u0040\\u005B-\\u0060\\u007B-\\u007F]+/g) ?? []\n\t);\n}\n"]}
@@ -0,0 +1,24 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ import { manual } from "./manual.js";
4
+ /**
5
+ * Return a function that can be used as a svelte preprocessor.
6
+ * @returns The preprocessor.
7
+ */
8
+ export function tsTransformersPreProcess() {
9
+ return {
10
+ markup: tsTransformersPreProcessMarkup
11
+ };
12
+ }
13
+ /**
14
+ * Convert the content with a svelte preprocessor.
15
+ * @param params The parameters for the preprocessor.
16
+ * @param params.content The content for the preprocessor.
17
+ * @returns The converted content.
18
+ */
19
+ async function tsTransformersPreProcessMarkup(params) {
20
+ return {
21
+ code: manual(params.content)
22
+ };
23
+ }
24
+ //# sourceMappingURL=svelte.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"svelte.js","sourceRoot":"","sources":["../../src/svelte.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;GAGG;AACH,MAAM,UAAU,wBAAwB;IACvC,OAAO;QACN,MAAM,EAAE,8BAA8B;KACtC,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,8BAA8B,CAAC,MAE7C;IACA,OAAO;QACN,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;KAC5B,CAAC;AACH,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { manual } from \"./manual.js\";\n\n/**\n * Return a function that can be used as a svelte preprocessor.\n * @returns The preprocessor.\n */\nexport function tsTransformersPreProcess(): { markup: unknown } {\n\treturn {\n\t\tmarkup: tsTransformersPreProcessMarkup\n\t};\n}\n\n/**\n * Convert the content with a svelte preprocessor.\n * @param params The parameters for the preprocessor.\n * @param params.content The content for the preprocessor.\n * @returns The converted content.\n */\nasync function tsTransformersPreProcessMarkup(params: {\n\tcontent: string;\n}): Promise<{ code: string }> {\n\treturn {\n\t\tcode: manual(params.content)\n\t};\n}\n"]}
@@ -1,19 +1,19 @@
1
- import * as ts from 'typescript';
2
-
3
1
  // Copyright 2024 IOTA Stiftung.
4
2
  // SPDX-License-Identifier: Apache-2.0.
3
+ import * as ts from "typescript";
4
+ import { camelCase, kebabCase } from "./stringHelper.js";
5
5
  /**
6
6
  * The transformer factory entry point.
7
7
  * @param context The context for the factory.
8
8
  * @returns The transformed node.
9
9
  */
10
- const transformerFactory = transformer;
10
+ export const transformerFactory = transformer;
11
11
  /**
12
12
  * Transform all the nodes in a context.
13
13
  * @param context The context to traverse.
14
14
  * @returns A transformer for the context.
15
15
  */
16
- function transformer(context) {
16
+ export function transformer(context) {
17
17
  return (node) => {
18
18
  if (ts.isSourceFile(node)) {
19
19
  return visitNodeAndChildren(context, node);
@@ -47,7 +47,10 @@ function visitNode(node) {
47
47
  }
48
48
  catch { }
49
49
  // 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) {
50
+ if ((expressionText === "nameof" ||
51
+ expressionText === "nameofKebabCase" ||
52
+ expressionText === "nameofCamelCase") &&
53
+ node.typeArguments?.length === 1) {
51
54
  let typeName;
52
55
  if (ts.isTypeReferenceNode(node.typeArguments[0])) {
53
56
  typeName = node.typeArguments[0].typeName.getText();
@@ -56,10 +59,20 @@ function visitNode(node) {
56
59
  typeName = `${node.typeArguments[0].elementType.getText()}[]`;
57
60
  }
58
61
  if (typeName) {
62
+ if (expressionText.endsWith("KebabCase")) {
63
+ return ts.factory.createStringLiteral(kebabCase(typeName));
64
+ }
65
+ else if (expressionText.endsWith("CamelCase")) {
66
+ return ts.factory.createStringLiteral(camelCase(typeName));
67
+ }
59
68
  return ts.factory.createStringLiteral(typeName);
60
69
  }
61
70
  }
62
- else if (expressionText === "nameof" && node.arguments && node.arguments.length >= 1) {
71
+ else if ((expressionText === "nameof" ||
72
+ expressionText === "nameofKebabCase" ||
73
+ expressionText === "nameofCamelCase") &&
74
+ node.arguments &&
75
+ node.arguments.length >= 1) {
63
76
  // This is an nameof(propName, ?optionalParent) call.
64
77
  // Return the whole property path as the string, but remove any chaining operators
65
78
  // The second parameter is an optional string, if set change the top level owner
@@ -72,11 +85,17 @@ function visitNode(node) {
72
85
  return ts.factory.createBinaryExpression(ts.factory.createIdentifier(node.arguments[1].getText()), ts.factory.createToken(ts.SyntaxKind.PlusToken), ts.factory.createStringLiteral(parts.join(".")));
73
86
  }
74
87
  }
88
+ if (expressionText.endsWith("KebabCase")) {
89
+ return ts.factory.createStringLiteral(kebabCase(propertyPath));
90
+ }
91
+ else if (expressionText.endsWith("CamelCase")) {
92
+ return ts.factory.createStringLiteral(camelCase(propertyPath));
93
+ }
75
94
  return ts.factory.createStringLiteral(propertyPath);
76
95
  }
77
96
  }
78
97
  else if (ts.isImportDeclaration(node) &&
79
- node.moduleSpecifier.getText().includes("@twin.org/nameof")) {
98
+ node.moduleSpecifier.getText().includes('"@twin.org/nameof"')) {
80
99
  // Is this an import of @twin.org/nameof
81
100
  // e.g. import { nameof } from "@twin.org/nameof";
82
101
  // if it is then return undefined to remove the node
@@ -84,66 +103,4 @@ function visitNode(node) {
84
103
  }
85
104
  return node;
86
105
  }
87
-
88
- // Copyright 2024 IOTA Stiftung.
89
- // SPDX-License-Identifier: Apache-2.0.
90
- /**
91
- * Replace the transformers manually.
92
- * @param content The content to replace the transformers in.
93
- * @returns The content with the transformers replace.
94
- */
95
- function manual(content) {
96
- if (typeof content === "string" && content.includes("nameof")) {
97
- // Remove the import
98
- content = content.replace(/import.*from "@twin\.org\/nameof";/g, "");
99
- // Replace the nameof<IMyObject>() with "IMyObject"
100
- // or the nameof<IMyObject<IType2>>() with "IMyObject"
101
- const nameRegEx = /nameof<(.*?)(?:<.*>)?>\(\)/g;
102
- content = content.replace(nameRegEx, '"$1"');
103
- // Replace the nameof(object?.prop) with "object.prop"
104
- const propRegEx = /nameof\((.*?)\)/g;
105
- content = content.replace(propRegEx, '"$1"');
106
- }
107
- return content;
108
- }
109
-
110
- // Copyright 2024 IOTA Stiftung.
111
- // SPDX-License-Identifier: Apache-2.0.
112
- /**
113
- * Return a function that can be used as a svelte preprocessor.
114
- * @returns The preprocessor.
115
- */
116
- function tsTransformersPreProcess() {
117
- return {
118
- markup: tsTransformersPreProcessMarkup
119
- };
120
- }
121
- /**
122
- * Convert the content with a svelte preprocessor.
123
- * @param params The parameters for the preprocessor.
124
- * @param params.content The content for the preprocessor.
125
- * @returns The converted content.
126
- */
127
- async function tsTransformersPreProcessMarkup(params) {
128
- return {
129
- code: manual(params.content)
130
- };
131
- }
132
-
133
- /**
134
- * Exports the factory.
135
- * @returns The factory.
136
- */
137
- const factory = () => transformerFactory;
138
- /**
139
- * Exports the factory version.
140
- * @returns The factory.
141
- */
142
- const version = "0.0.2-next.8"; // x-release-please-version
143
- /**
144
- * Exports the factory name.
145
- * @returns The factory.
146
- */
147
- const name = "@twin.org/nameof-transformer";
148
-
149
- export { factory as default, factory, manual, name, tsTransformersPreProcess, version };
106
+ //# sourceMappingURL=transformer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transformer.js","sourceRoot":"","sources":["../../src/transformer.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport * as ts from \"typescript\";\nimport { camelCase, kebabCase } from \"./stringHelper.js\";\n\n/**\n * The transformer factory entry point.\n * @param context The context for the factory.\n * @returns The transformed node.\n */\nexport const transformerFactory: ts.TransformerFactory<ts.Node> = transformer;\n\n/**\n * Transform all the nodes in a context.\n * @param context The context to traverse.\n * @returns A transformer for the context.\n */\nexport function transformer(context: ts.TransformationContext): ts.Transformer<ts.Node> {\n\treturn (node: ts.Node) => {\n\t\tif (ts.isSourceFile(node)) {\n\t\t\treturn visitNodeAndChildren(context, node);\n\t\t}\n\n\t\treturn node;\n\t};\n}\n\n/**\n * Visit the node and children in a context.\n * @param context The context to traverse.\n * @param node The node being visited.\n * @returns The updated node.\n */\nfunction visitNodeAndChildren(context: ts.TransformationContext, node: ts.Node): ts.Node {\n\tif (!node) {\n\t\treturn node;\n\t}\n\n\tnode = ts.visitEachChild(node, childNode => visitNodeAndChildren(context, childNode), context);\n\n\treturn visitNode(node);\n}\n\n/**\n * Update a node in the tree.\n * @param node The node to update.\n * @returns The updated node.\n */\nfunction visitNode(node: ts.Node): ts.Node {\n\tif (ts.isCallExpression(node)) {\n\t\tlet expressionText;\n\n\t\ttry {\n\t\t\texpressionText = node.expression.getText();\n\t\t} catch {}\n\n\t\t// Is this a call to nameof<Type>(), if so just replace with a string e.g. \"Type\"\n\t\tif (\n\t\t\t(expressionText === \"nameof\" ||\n\t\t\t\texpressionText === \"nameofKebabCase\" ||\n\t\t\t\texpressionText === \"nameofCamelCase\") &&\n\t\t\tnode.typeArguments?.length === 1\n\t\t) {\n\t\t\tlet typeName;\n\t\t\tif (ts.isTypeReferenceNode(node.typeArguments[0])) {\n\t\t\t\ttypeName = node.typeArguments[0].typeName.getText();\n\t\t\t} else if (ts.isArrayTypeNode(node.typeArguments[0])) {\n\t\t\t\ttypeName = `${node.typeArguments[0].elementType.getText()}[]`;\n\t\t\t}\n\n\t\t\tif (typeName) {\n\t\t\t\tif (expressionText.endsWith(\"KebabCase\")) {\n\t\t\t\t\treturn ts.factory.createStringLiteral(kebabCase(typeName));\n\t\t\t\t} else if (expressionText.endsWith(\"CamelCase\")) {\n\t\t\t\t\treturn ts.factory.createStringLiteral(camelCase(typeName));\n\t\t\t\t}\n\t\t\t\treturn ts.factory.createStringLiteral(typeName);\n\t\t\t}\n\t\t} else if (\n\t\t\t(expressionText === \"nameof\" ||\n\t\t\t\texpressionText === \"nameofKebabCase\" ||\n\t\t\t\texpressionText === \"nameofCamelCase\") &&\n\t\t\tnode.arguments &&\n\t\t\tnode.arguments.length >= 1\n\t\t) {\n\t\t\t// This is an nameof(propName, ?optionalParent) call.\n\t\t\t// Return the whole property path as the string, but remove any chaining operators\n\t\t\t// The second parameter is an optional string, if set change the top level owner\n\t\t\t// in the property path\n\t\t\tconst propertyPath = node.arguments[0].getText().replace(/\\?/g, \"\");\n\t\t\tif (node.arguments.length === 2) {\n\t\t\t\tconst parts = propertyPath.split(\".\");\n\t\t\t\tif (parts.length > 1) {\n\t\t\t\t\tparts[0] = \"\";\n\t\t\t\t\treturn ts.factory.createBinaryExpression(\n\t\t\t\t\t\tts.factory.createIdentifier(node.arguments[1].getText()),\n\t\t\t\t\t\tts.factory.createToken(ts.SyntaxKind.PlusToken),\n\t\t\t\t\t\tts.factory.createStringLiteral(parts.join(\".\"))\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (expressionText.endsWith(\"KebabCase\")) {\n\t\t\t\treturn ts.factory.createStringLiteral(kebabCase(propertyPath));\n\t\t\t} else if (expressionText.endsWith(\"CamelCase\")) {\n\t\t\t\treturn ts.factory.createStringLiteral(camelCase(propertyPath));\n\t\t\t}\n\t\t\treturn ts.factory.createStringLiteral(propertyPath);\n\t\t}\n\t} else if (\n\t\tts.isImportDeclaration(node) &&\n\t\tnode.moduleSpecifier.getText().includes('\"@twin.org/nameof\"')\n\t) {\n\t\t// Is this an import of @twin.org/nameof\n\t\t// e.g. import { nameof } from \"@twin.org/nameof\";\n\t\t// if it is then return undefined to remove the node\n\t\treturn undefined as unknown as ts.Node;\n\t}\n\n\treturn node;\n}\n"]}
@@ -3,17 +3,17 @@ import type * as ts from "typescript";
3
3
  * Exports the factory.
4
4
  * @returns The factory.
5
5
  */
6
- export declare const factory: () => ts.TransformerFactory<ts.Node>;
6
+ export declare function factory(): ts.TransformerFactory<ts.Node>;
7
7
  /**
8
8
  * Exports the factory version.
9
9
  * @returns The factory.
10
10
  */
11
- export declare const version = "0.0.2-next.8";
11
+ export declare const version = "0.0.2";
12
12
  /**
13
13
  * Exports the factory name.
14
14
  * @returns The factory.
15
15
  */
16
16
  export declare const name = "@twin.org/nameof-transformer";
17
- export * from "./manual";
18
- export * from "./svelte";
17
+ export * from "./manual.js";
18
+ export * from "./svelte.js";
19
19
  export default 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[];