@ai-dev-tools/csharp-copilot-core 0.0.33 → 0.0.35
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/out/batch/generateCodeTests.js +22 -6
- package/out/batch/generateCodeTests.js.map +1 -1
- package/out/changedFilesProcessor/processChangedFiles.d.ts +9 -0
- package/out/changedFilesProcessor/processChangedFiles.js +156 -0
- package/out/changedFilesProcessor/processChangedFiles.js.map +1 -0
- package/out/codebk/prompts/buildAfGuidelines_20251226.liquid +15 -0
- package/out/codebk/prompts/general/generalUtGuidelines_20251226.liquid +16 -0
- package/out/codebk/prompts/xap/xapUtGuideline_20251225.liquid +37 -0
- package/out/codebk/prompts/xap/xapUtGuideline_20251226.liquid +49 -0
- package/out/command/index.js +32 -0
- package/out/command/index.js.map +1 -1
- package/out/command/utGenWrapper.js +85 -4
- package/out/command/utGenWrapper.js.map +1 -1
- package/out/gen/autoFix.d.ts +2 -2
- package/out/gen/autoFix.js +88 -31
- package/out/gen/autoFix.js.map +1 -1
- package/out/gen/csharpUtGen.d.ts +1 -1
- package/out/gen/csharpUtGen.js +16 -13
- package/out/gen/csharpUtGen.js.map +1 -1
- package/out/gen/ensureValidLLMResponse.d.ts +5 -1
- package/out/gen/ensureValidLLMResponse.js +15 -3
- package/out/gen/ensureValidLLMResponse.js.map +1 -1
- package/out/gen/postGen/postGenMoreUTProcess.d.ts +25 -0
- package/out/gen/postGen/postGenMoreUTProcess.js +502 -0
- package/out/gen/postGen/postGenMoreUTProcess.js.map +1 -0
- package/out/gen/postGen/postGenProcess.d.ts +1 -1
- package/out/gen/postGen/postGenProcess.js +7 -7
- package/out/gen/postGen/postGenProcess.js.map +1 -1
- package/out/gen/postGen/repairRequiredNameSpaces.d.ts +17 -0
- package/out/gen/postGen/repairRequiredNameSpaces.js +87 -20
- package/out/gen/postGen/repairRequiredNameSpaces.js.map +1 -1
- package/out/llm/preparePrompt.d.ts +2 -1
- package/out/llm/preparePrompt.js +38 -4
- package/out/llm/preparePrompt.js.map +1 -1
- package/out/llm/prompt/buildAfGuidelines.liquid +8 -8
- package/out/llm/prompt/general/generalUtGuidelines.liquid +3 -0
- package/out/llm/prompt/moreUT/generateMoreUTSourceCode.liquid +4 -0
- package/out/llm/prompt/moreUT/generateMoreUtAutoFix.liquid +45 -0
- package/out/llm/prompt/moreUT/generateMoreUtTemplate.liquid +115 -0
- package/out/llm/prompt/moreUT/generateMoreUtTestCode.liquid +5 -0
- package/out/llm/prompt/moreUT/utGenerationGuidelines.liquid +15 -0
- package/out/llm/prompt/xap/xapUtGuideline.liquid +66 -15
- package/out/types/changedFilesResult.d.ts +37 -0
- package/out/types/changedFilesResult.js +3 -0
- package/out/types/changedFilesResult.js.map +1 -0
- package/out/types/constants.d.ts +1 -0
- package/out/types/constants.js +2 -1
- package/out/types/constants.js.map +1 -1
- package/out/types/genResult.d.ts +1 -1
- package/out/types/genResult.js.map +1 -1
- package/out/utils/checkXapCode.d.ts +1 -1
- package/out/utils/checkXapCode.js +14 -2
- package/out/utils/checkXapCode.js.map +1 -1
- package/out/utils/fileUtils.d.ts +1 -0
- package/out/utils/fileUtils.js +13 -0
- package/out/utils/fileUtils.js.map +1 -1
- package/out/utils/getCodeStructurePath.d.ts +4 -0
- package/out/utils/getCodeStructurePath.js +30 -0
- package/out/utils/getCodeStructurePath.js.map +1 -1
- package/out/utils/getTestFile.d.ts +18 -8
- package/out/utils/getTestFile.js +735 -62
- package/out/utils/getTestFile.js.map +1 -1
- package/out/utils/removeFailedTestMethods.d.ts +8 -0
- package/out/utils/removeFailedTestMethods.js +363 -0
- package/out/utils/removeFailedTestMethods.js.map +1 -1
- package/out/utils/verifyGeneratedCode.d.ts +2 -0
- package/out/utils/verifyGeneratedCode.js +17 -0
- package/out/utils/verifyGeneratedCode.js.map +1 -0
- package/package.json +4 -3
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
You are a highly skilled software engineer specializing in C# unit testing with extensive knowledge in test frameworks, test patterns, and best practices.
|
|
2
|
+
You are tasked to write more unit test code with the given source code and dependency code and unit test code to improve the code coverage. The higher the coverage rate, the better.
|
|
3
|
+
You will be given source code, its dependency code, and its test class's code.
|
|
4
|
+
|
|
5
|
+
====
|
|
6
|
+
|
|
7
|
+
Rules
|
|
8
|
+
|
|
9
|
+
**LEARN FROM THE GIVEN TEST CODE**: The existing test code is human-reviewed and represents the preferred coding style and patterns. When in conflict with any guidelines below, follow the patterns you observe in the given test code as they take precedence.
|
|
10
|
+
|
|
11
|
+
{% if isXapTest %}
|
|
12
|
+
The user provided source code is using XAP framework, which has specific rules for unit tests.
|
|
13
|
+
These rules are defined in the XAP UNIT TEST Guidelines. Please follow these rules strictly when generating unit tests. The rules in XAP UNIT TEST Guidelines should take precedence over the rules in GENERAL UNIT TEST Guidelines.
|
|
14
|
+
{% endif %}
|
|
15
|
+
{% if isXapTest %}
|
|
16
|
+
{% include 'xap/xapUtGuideline' %}
|
|
17
|
+
{% endif %}
|
|
18
|
+
|
|
19
|
+
# General Unit Test Guidelines
|
|
20
|
+
|
|
21
|
+
- The user will provide the source code, its dependency code, and its test code directly in their messages.
|
|
22
|
+
- **MUST NOT** call private methods or properties in test code.
|
|
23
|
+
- **MUST NOT** contain any comments or explanations in test code.
|
|
24
|
+
- Ensure the test code MUST has no syntax errors.
|
|
25
|
+
- Test method names must follow the pattern: [MethodName]_[Scenario]_[ExpectedResult].
|
|
26
|
+
- **MUST reuse existing helper methods** defined in the given test code when they provide the needed functionality. Only create new helper methods when existing ones cannot fulfill the requirement. Do NOT create new helper methods that duplicate or overlap with existing ones (e.g., do NOT create a private version of an existing public helper).
|
|
27
|
+
- If source code namespace is not already imported in the given test code, include it in the USING_STATEMENTS section.
|
|
28
|
+
- If any new .Net namespaces are required by the new test code, include them in the USING_STATEMENTS section. Like:
|
|
29
|
+
- .NET built-in types (e.g., `List<T>`, `IEnumerable<T>`, `Task`, `Assert`, `Moq.Mock`, etc.).
|
|
30
|
+
- Any attribute classes (e.g., `[TestMethod]`, `[TestClass]`, etc.).
|
|
31
|
+
- Any LINQ or threading related classes (e.g., `System.Linq`, `System.Threading.Tasks`).
|
|
32
|
+
- **MUST NOT** generate tests for the methods that are attributed with **[ExcludeFromCodeCoverage]**.
|
|
33
|
+
- The generated test code snippets must be syntactically correct and compilable after being assembled into the original test file.
|
|
34
|
+
- Must follow styling practice as you see in given test code.
|
|
35
|
+
- Must implement the test code and not leave it on the user to complete the implementations.
|
|
36
|
+
|
|
37
|
+
====
|
|
38
|
+
|
|
39
|
+
OBJECTIVE
|
|
40
|
+
|
|
41
|
+
You are tasked to write more unit test code, breaking it down into clear steps and working through them methodically.
|
|
42
|
+
|
|
43
|
+
- **FIRST, carefully analyze the given test code to identify ALL existing helper methods** (look for non-test methods like Mock*, Create*, Setup*, etc.). Make a mental note of their names, signatures, and purposes.
|
|
44
|
+
- Analyze the user's source code and existing test code, identify uncovered code paths and edge cases.
|
|
45
|
+
- Set clear, achievable goals to generate additional unit tests. Prioritize these goals in a logical order.
|
|
46
|
+
- Work through these goals sequentially, each goal should correspond to a distinct step in your problem-solving process.
|
|
47
|
+
- **When writing new test methods, call the existing helper methods directly. Do NOT redefine them in HELPER_CODE.**
|
|
48
|
+
- You are STRICTLY FORBIDDEN to contain analysis steps in your response. Just return the code using the OUTPUT FORMAT below.
|
|
49
|
+
|
|
50
|
+
====
|
|
51
|
+
|
|
52
|
+
OUTPUT FORMAT
|
|
53
|
+
|
|
54
|
+
You MUST return the newly added test code in the following structured format. Do NOT return the complete test file, only return the NEW code to be added.
|
|
55
|
+
|
|
56
|
+
The output MUST contain exactly three sections in the following order:
|
|
57
|
+
|
|
58
|
+
1. **USING_STATEMENTS**: New using statements that need to be added (if any). Only include using statements that are NOT already in the given test code.
|
|
59
|
+
|
|
60
|
+
2. **TEST_METHODS**: The new test methods to be added. These methods will be inserted into the existing test class.
|
|
61
|
+
|
|
62
|
+
3. **HELPER_CODE**: Any helper methods, helper classes, or additional code needed by the new test methods (if any). This code will be inserted right after the TEST_METHODS.
|
|
63
|
+
|
|
64
|
+
Use the following markdown format:
|
|
65
|
+
|
|
66
|
+
```USING_STATEMENTS
|
|
67
|
+
using SomeNamespace;
|
|
68
|
+
using AnotherNamespace;
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
```TEST_METHODS
|
|
72
|
+
[TestMethod]
|
|
73
|
+
public void MethodName_Scenario_ExpectedResult()
|
|
74
|
+
{
|
|
75
|
+
var result = targetObject.MethodName();
|
|
76
|
+
Assert.AreEqual(expected, result);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
[TestMethod]
|
|
80
|
+
public void AnotherMethod_Scenario_ExpectedResult()
|
|
81
|
+
{
|
|
82
|
+
var result = targetObject.AnotherMethod(input);
|
|
83
|
+
Assert.IsNotNull(result);
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
```HELPER_CODE
|
|
88
|
+
private SomeType CreateTestData()
|
|
89
|
+
{
|
|
90
|
+
return new SomeType { Property = value };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private class TestableTarget : TargetClass
|
|
94
|
+
{
|
|
95
|
+
public bool WasCalled { get; set; }
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**IMPORTANT RULES:**
|
|
100
|
+
- If no new using statements are needed, leave the USING_STATEMENTS section empty but still include it.
|
|
101
|
+
- If no helper code is needed, leave the HELPER_CODE section empty but still include it.
|
|
102
|
+
- Do NOT include namespace declaration or class declaration in TEST_METHODS or HELPER_CODE.
|
|
103
|
+
- Do NOT duplicate any existing test methods from the given test code.
|
|
104
|
+
- **CRITICAL: Scan the entire given test code for existing helper methods (non-[TestMethod] methods). If MockXxx, CreateXxx, SetupXxx, or similar helper methods already exist, call them directly in your TEST_METHODS. Do NOT redefine them in HELPER_CODE, regardless of access modifier (public/private/internal).**
|
|
105
|
+
- HELPER_CODE must ONLY contain genuinely NEW helper methods that provide functionality NOT already available in any existing helper method.
|
|
106
|
+
- When in doubt whether a helper exists, assume it does and leave HELPER_CODE empty.
|
|
107
|
+
|
|
108
|
+
====
|
|
109
|
+
|
|
110
|
+
USER'S CUSTOM INSTRUCTIONS
|
|
111
|
+
|
|
112
|
+
The following additional instructions are provided by the user, and should be followed to the best of your ability without interfering with the and guidelines.
|
|
113
|
+
|
|
114
|
+
Language Preference:
|
|
115
|
+
You should always speak and think in the English language.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
### General Rules
|
|
2
|
+
- **MUST NOT** call private methods or properties in test code.
|
|
3
|
+
- **MUST NOT** access internal members unless the assembly has [InternalsVisibleTo] for the test project.
|
|
4
|
+
|
|
5
|
+
{% if isXapCode %}
|
|
6
|
+
### XAP Rules
|
|
7
|
+
- MUST use **ExecutionServices.CreateInstance<I{ClassName}>()** to create Xap class instance, where the interface name is the class name prefixed with "I".
|
|
8
|
+
- The parameters of **Execute** method with types: **PluginServices**, **PluginOutput<T>**, **CollectionPluginOutput<IEnumerable<T>>**, or attributed with **[ConfigFile]** MUST be deleted when calling Execute.
|
|
9
|
+
- **MUST NOT** mock these deleted types (PluginServices, PluginOutput, CollectionPluginOutput, ConfigFile parameter types).
|
|
10
|
+
- For methods **other than Execute** that have **PluginServices** parameter, MUST use **ExecutionServices.CreatePluginServices()** to create the PluginServices instance.
|
|
11
|
+
- For methods that require **PluginLogger** as a parameter, MUST obtain it from **pluginServices.Logger** property.
|
|
12
|
+
- For Bond structures: MUST first create PluginServices, then use **pluginServices.CreateInstance<{StructName}>()** to create Bond struct instances.
|
|
13
|
+
- For Bond blob fields, use **pluginServices.CreateInstance<XapBlob>(byteArray)**.
|
|
14
|
+
- For Bond bonded<T> fields, use **pluginServices.CreateInstance<XapBonded<T>>(nestedInstance)**.
|
|
15
|
+
{% endif %}
|
|
@@ -1,33 +1,84 @@
|
|
|
1
1
|
# Xap Unit Test Guidelines
|
|
2
2
|
|
|
3
3
|
- Xap class is a class that inherits one of these interfaces: IPlugin, IConditionPlugin, Workflow, IExperiment, IPluginDataStore, IAsyncPlugin and implements an Execute() method.
|
|
4
|
+
- **MUST NOT call private methods in test code** - this rule from General Guidelines still applies to XAP tests.
|
|
4
5
|
- MUST use ExecutionServices.CreateInstance<I{ClassName}>() to create Xap class instance, where the interface name is the class name prefixed with "I".
|
|
5
6
|
Example: For Xap class SampleWorkflow, create instance MUST be like: **var sampleWorkflow = ExecutionServices.CreateInstance<ISampleWorkflow>();**
|
|
6
|
-
- The parameters of **Execute** method with types: **PluginServices**, **PluginOutput<T>**, or attributed with **[ConfigFile("{configFileName}")]** MUST be deleted when using Xap class instance to call the Execute method.
|
|
7
|
-
- Xap
|
|
7
|
+
- The parameters of **Execute** method with types: **PluginServices**, **PluginOutput<T>**, **CollectionPluginOutput<IEnumerable<T>>**, or attributed with **[ConfigFile("{configFileName}")]** MUST be deleted when using Xap class instance to call the Execute method.
|
|
8
|
+
- Xap framework will take care these deleted parameters, NEVER try to mock or create these deleted types, it's invalid and forbidden.
|
|
8
9
|
- **MUST NOT** mock these deleted types' object, even if its methods or properties are used in the source code.
|
|
9
10
|
- For Remaining parameters,
|
|
10
11
|
- MUST pass in exact type as declared in source code.
|
|
11
12
|
- MUST keep original parameter order.
|
|
12
13
|
- MUST wrap each parameter with Task.FromResult(value).
|
|
13
14
|
Example:
|
|
14
|
-
The Execute method of Xap
|
|
15
|
-
Base on above declared deleted types, **MUST delete** these
|
|
15
|
+
The Execute method of Xap class SampleWorkflow is: **PluginResult Execute(PluginServices ps, PluginOutput<Resp> resp, CollectionPluginOutput<IEnumerable<RespItem>> respList, [ConfigFile("config.ini")] EplantConfig eplantConfig, OsResponse osResp = null, EplantRequest req = null)**,
|
|
16
|
+
Base on above declared deleted types, **MUST delete** these four parameters: PluginServices ps, PluginOutput<Resp> resp, CollectionPluginOutput<IEnumerable<RespItem>> respList, [ConfigFile("config.ini")] EplantConfig eplantConfig,
|
|
16
17
|
call the Execute using Xap class instance MUST be like: **var pluginResult = sampleWorkflow.Execute(Task.FromResult(osResp), Task.FromResult(req)).Result;**
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
- For Execute method null parameter handling:
|
|
19
|
+
- If a remaining parameter (after deleting PluginServices/PluginOutput/ConfigFile parameters) **does NOT have a default value**, and you pass **null** to it, Xap framework will NOT trigger the Execute method and the result will be **null**.
|
|
20
|
+
- In this case, **MUST** assert that the result is null.
|
|
21
|
+
- If the parameter **has a default value** (e.g., **InputParameter input = null**), passing null is valid and Execute will be triggered normally.
|
|
22
|
+
Example:
|
|
23
|
+
For Execute method: **PluginResult Execute(PluginServices ps, InputParameter inputParameter)** (inputParameter has NO default value),
|
|
24
|
+
When testing with null: **var result = sampleWorkflow.Execute(Task.FromResult<InputParameter>(null)).Result;**
|
|
25
|
+
MUST assert result is null: **Assert.IsNull(result);**
|
|
26
|
+
- The Execute method **MAY have zero, one, or multiple** parameters with type **PluginOutput<T>** and/or **CollectionPluginOutput<IEnumerable<T>>**. These parameters MUST be treated as method outputs.
|
|
27
|
+
- For **PluginOutput<T>**: **T** is the type of output value.
|
|
28
|
+
- For **CollectionPluginOutput<IEnumerable<T>>**: **IEnumerable<T>** is the type of output value.
|
|
29
|
+
- MUST use the parameter name to access the output by the Xap instance.
|
|
30
|
+
- MUST use **Result** property to access the output value in **PluginOutput<T>** or **CollectionPluginOutput<IEnumerable<T>>**.
|
|
31
|
+
- MUST assert **each PluginOutput<T> and CollectionPluginOutput<IEnumerable<T>> parameter's value** that exists in the Execute method.
|
|
32
|
+
Example (below shows both types together, but each can exist independently or not at all):
|
|
33
|
+
The Execute method of Xap class SampleWorkflow is: **PluginResult Execute(PluginServices ps, PluginOutput<Resp> resp, CollectionPluginOutput<IEnumerable<RespItem>> respList, [ConfigFile("config.ini")] EplantConfig eplantConfig, OsResponse osResp = null, EplantRequest req = null)**,
|
|
34
|
+
Access PluginOutput<T> output: **sampleWorkflow.resp** (type: PluginOutput<Resp>)
|
|
35
|
+
Get the value from PluginOutput<T>: **sampleWorkflow.resp.Result** (type: Resp)
|
|
36
|
+
Get a field from PluginOutput<T> value: **sampleWorkflow.resp.Result.Id** (assume Resp has field Id)
|
|
37
|
+
Assert PluginOutput<T>: **Assert.NotNull(sampleWorkflow.resp.Result); Assert.AreEqual(sampleWorkflow.resp.Result.Id, "expectedId");**
|
|
38
|
+
Access CollectionPluginOutput<IEnumerable<T>> output: **sampleWorkflow.respList** (type: CollectionPluginOutput<IEnumerable<RespItem>>)
|
|
39
|
+
Get the collection from CollectionPluginOutput<IEnumerable<T>>: **sampleWorkflow.respList.Result** (type: IEnumerable<RespItem>)
|
|
40
|
+
Assert CollectionPluginOutput<IEnumerable<T>>: **Assert.NotNull(sampleWorkflow.respList.Result); Assert.IsTrue(sampleWorkflow.respList.Result.Any());**
|
|
41
|
+
- For methods **other than Execute method** that have **PluginServices** type parameter, MUST use **ExecutionServices.CreatePluginServices()** to create the PluginServices instance.
|
|
42
|
+
Example:
|
|
43
|
+
For a method declared as: **public static int SomeHowMethod(PluginServices pluginServices, ParameterType1 parameter1)**,
|
|
44
|
+
MUST create PluginServices instance like: **var pluginServices = ExecutionServices.CreatePluginServices();**
|
|
45
|
+
Then call the method like: **var result = SomeHowMethod(pluginServices, parameter1Value);**
|
|
46
|
+
- For methods that require **PluginLogger** as a parameter, MUST obtain it from PluginServices.Logger property:
|
|
47
|
+
```csharp
|
|
48
|
+
var pluginServices = ExecutionServices.CreatePluginServices();
|
|
49
|
+
PluginLogger pluginLogger = pluginServices.Logger;
|
|
50
|
+
```
|
|
51
|
+
Then pass the pluginLogger to the method that requires it.
|
|
26
52
|
- The Bond structures MUST be treated as regular C# class in test code:
|
|
27
53
|
- **MUST** import **Bond namespace** before using the Bond structure in test code
|
|
28
54
|
Example: The namespace in bond structure is like: **namespace SharedSegments.Weather.OneService**, to use this bond structure, **MUST** add: **using SharedSegments.Weather.OneService** in test code.
|
|
29
|
-
- MUST use
|
|
30
|
-
|
|
55
|
+
- MUST first create PluginServices instance, then use it to create Bond struct instances:
|
|
56
|
+
- First: **var pluginServices = ExecutionServices.CreatePluginServices();**
|
|
57
|
+
- Then: **pluginServices.CreateInstance<{StructName}>();**
|
|
58
|
+
Example: For a Bond structure named **SampleBondStructure**, create bond instance **MUST** be like:
|
|
59
|
+
```csharp
|
|
60
|
+
var pluginServices = ExecutionServices.CreatePluginServices();
|
|
61
|
+
var subResponse = pluginServices.CreateInstance<SampleBondStructure>();
|
|
62
|
+
```
|
|
63
|
+
- For Bond structure fields with **blob** type, MUST use **pluginServices.CreateInstance<XapBlob>()** with a **byte array** parameter to assign value.
|
|
64
|
+
Example:
|
|
65
|
+
For a Bond structure: **struct SampleBondStructure { 1: required blob SampleBlobTypeElement; }**
|
|
66
|
+
Assign blob field like: **sampleBondStructure.SampleBlobTypeElement = pluginServices.CreateInstance<XapBlob>(Encoding.UTF8.GetBytes("SomeContent"));**
|
|
67
|
+
Where **Encoding.UTF8.GetBytes("SomeContent")** returns a byte array.
|
|
68
|
+
For an empty byte array, **MUST** use **Array.Empty<byte>()**: **sampleBondStructure.SampleBlobTypeElement = pluginServices.CreateInstance<XapBlob>(Array.Empty<byte>());**
|
|
69
|
+
- For Bond structure fields wrapped by **bonded**, MUST use **pluginServices.CreateInstance<XapBonded<T>>()** with the nested structure instance as parameter to assign value.
|
|
70
|
+
Example:
|
|
71
|
+
For Bond structures:
|
|
72
|
+
```csharp
|
|
73
|
+
struct SampleBondStructure1 {
|
|
74
|
+
1: required bonded<SampleBondStructure2> Value;
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
Assume structure1 is instance of SampleBondStructure1:
|
|
78
|
+
```csharp
|
|
79
|
+
var structure2 = pluginServices.CreateInstance<SampleBondStructure2>();
|
|
80
|
+
structure1.Value = pluginServices.CreateInstance<XapBonded<SampleBondStructure2>>(structure2);
|
|
81
|
+
```
|
|
31
82
|
- MUST not access the fields that are not defined in bond structure, it's invalid and forbidden.
|
|
32
83
|
- MUST treated the fields as **required** if they **are not** decorated with **optional** in bond structure
|
|
33
84
|
- **MUST** assign a valid, non-null value to **required field** that are **NOT decorated** with **optional** explicitly.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a changed file entry from the config file.
|
|
3
|
+
*/
|
|
4
|
+
export interface ChangedFileEntry {
|
|
5
|
+
filepath: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Result of categorizing changed CS files.
|
|
9
|
+
*/
|
|
10
|
+
export interface CategorizedFiles {
|
|
11
|
+
testFiles: ChangedFileEntry[];
|
|
12
|
+
sourceFiles: ChangedFileEntry[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Processed source file info with all related paths.
|
|
16
|
+
*/
|
|
17
|
+
export interface ProcessedSourceFile {
|
|
18
|
+
sourceFile: ChangedFileEntry;
|
|
19
|
+
testFilePath: string | null;
|
|
20
|
+
runsettingsFilePath: string | null;
|
|
21
|
+
solutionFilePath: string | null;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Changed file entry in the final result.
|
|
25
|
+
*/
|
|
26
|
+
export interface ChangedFileResult {
|
|
27
|
+
filepath: string;
|
|
28
|
+
testfilepath: string | null;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Final result format for CI pipeline consumption.
|
|
32
|
+
*/
|
|
33
|
+
export interface ProcessChangedFilesResult {
|
|
34
|
+
solutionFilePath: string | null;
|
|
35
|
+
runsettingsFilePath: string | null;
|
|
36
|
+
changedFiles: ChangedFileResult[];
|
|
37
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"changedFilesResult.js","sourceRoot":"","sources":["../../src/types/changedFilesResult.ts"],"names":[],"mappings":"","sourcesContent":["/**\r\n * Represents a changed file entry from the config file.\r\n */\r\nexport interface ChangedFileEntry {\r\n filepath: string;\r\n}\r\n\r\n/**\r\n * Result of categorizing changed CS files.\r\n */\r\nexport interface CategorizedFiles {\r\n testFiles: ChangedFileEntry[];\r\n sourceFiles: ChangedFileEntry[];\r\n}\r\n\r\n/**\r\n * Processed source file info with all related paths.\r\n */\r\nexport interface ProcessedSourceFile {\r\n sourceFile: ChangedFileEntry;\r\n testFilePath: string | null;\r\n runsettingsFilePath: string | null;\r\n solutionFilePath: string | null;\r\n}\r\n\r\n/**\r\n * Changed file entry in the final result.\r\n */\r\nexport interface ChangedFileResult {\r\n filepath: string;\r\n testfilepath: string | null;\r\n}\r\n\r\n/**\r\n * Final result format for CI pipeline consumption.\r\n */\r\nexport interface ProcessChangedFilesResult {\r\n solutionFilePath: string | null;\r\n runsettingsFilePath: string | null;\r\n changedFiles: ChangedFileResult[];\r\n}\r\n"]}
|
package/out/types/constants.d.ts
CHANGED
|
@@ -8,3 +8,4 @@ export declare const NAMESPACE = "namespace";
|
|
|
8
8
|
export declare const MSTESTFRAMEWORK = "MSTest";
|
|
9
9
|
export declare const NUNITTESTFRAMEWORK = "NUnit";
|
|
10
10
|
export declare const XUNITTESTFRAMEWORK = "xUnit";
|
|
11
|
+
export declare const XapBondRelatedNamespace = "using Microsoft.Bing.Xap.CodeGenCollections.Generic;";
|
package/out/types/constants.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.XUNITTESTFRAMEWORK = exports.NUNITTESTFRAMEWORK = exports.MSTESTFRAMEWORK = exports.NAMESPACE = exports.AICONTRIBUTED = exports.LINESEPARATOR = exports.PIPELINE = exports.CSVSCODEPLUGIN = exports.CSHARPUTGEN = exports.CSVSPLUGIN = void 0;
|
|
3
|
+
exports.XapBondRelatedNamespace = exports.XUNITTESTFRAMEWORK = exports.NUNITTESTFRAMEWORK = exports.MSTESTFRAMEWORK = exports.NAMESPACE = exports.AICONTRIBUTED = exports.LINESEPARATOR = exports.PIPELINE = exports.CSVSCODEPLUGIN = exports.CSHARPUTGEN = exports.CSVSPLUGIN = void 0;
|
|
4
4
|
exports.CSVSPLUGIN = 'csvsplugin';
|
|
5
5
|
exports.CSHARPUTGEN = 'csharpUtGen';
|
|
6
6
|
exports.CSVSCODEPLUGIN = 'csVsCodePlugin';
|
|
@@ -11,4 +11,5 @@ exports.NAMESPACE = 'namespace';
|
|
|
11
11
|
exports.MSTESTFRAMEWORK = 'MSTest';
|
|
12
12
|
exports.NUNITTESTFRAMEWORK = 'NUnit';
|
|
13
13
|
exports.XUNITTESTFRAMEWORK = 'xUnit';
|
|
14
|
+
exports.XapBondRelatedNamespace = 'using Microsoft.Bing.Xap.CodeGenCollections.Generic;';
|
|
14
15
|
//# sourceMappingURL=constants.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/types/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,UAAU,GAAG,YAAY,CAAC;AAC1B,QAAA,WAAW,GAAG,aAAa,CAAC;AAC5B,QAAA,cAAc,GAAG,gBAAgB,CAAC;AAClC,QAAA,QAAQ,GAAG,UAAU,CAAC;AACtB,QAAA,aAAa,GAAG,OAAO,CAAC;AACxB,QAAA,aAAa,GAAG,gBAAgB,CAAC;AACjC,QAAA,SAAS,GAAG,WAAW,CAAC;AACxB,QAAA,eAAe,GAAG,QAAQ,CAAC;AAC3B,QAAA,kBAAkB,GAAG,OAAO,CAAC;AAC7B,QAAA,kBAAkB,GAAG,OAAO,CAAC","sourcesContent":["export const CSVSPLUGIN = 'csvsplugin';\r\nexport const CSHARPUTGEN = 'csharpUtGen';\r\nexport const CSVSCODEPLUGIN = 'csVsCodePlugin';\r\nexport const PIPELINE = 'pipeline';\r\nexport const LINESEPARATOR = /\\r?\\n/;\r\nexport const AICONTRIBUTED = '@aiContributed';\r\nexport const NAMESPACE = 'namespace';\r\nexport const MSTESTFRAMEWORK = 'MSTest';\r\nexport const NUNITTESTFRAMEWORK = 'NUnit';\r\nexport const XUNITTESTFRAMEWORK = 'xUnit';\r\n"]}
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/types/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,UAAU,GAAG,YAAY,CAAC;AAC1B,QAAA,WAAW,GAAG,aAAa,CAAC;AAC5B,QAAA,cAAc,GAAG,gBAAgB,CAAC;AAClC,QAAA,QAAQ,GAAG,UAAU,CAAC;AACtB,QAAA,aAAa,GAAG,OAAO,CAAC;AACxB,QAAA,aAAa,GAAG,gBAAgB,CAAC;AACjC,QAAA,SAAS,GAAG,WAAW,CAAC;AACxB,QAAA,eAAe,GAAG,QAAQ,CAAC;AAC3B,QAAA,kBAAkB,GAAG,OAAO,CAAC;AAC7B,QAAA,kBAAkB,GAAG,OAAO,CAAC;AAC7B,QAAA,uBAAuB,GAAG,sDAAsD,CAAC","sourcesContent":["export const CSVSPLUGIN = 'csvsplugin';\r\nexport const CSHARPUTGEN = 'csharpUtGen';\r\nexport const CSVSCODEPLUGIN = 'csVsCodePlugin';\r\nexport const PIPELINE = 'pipeline';\r\nexport const LINESEPARATOR = /\\r?\\n/;\r\nexport const AICONTRIBUTED = '@aiContributed';\r\nexport const NAMESPACE = 'namespace';\r\nexport const MSTESTFRAMEWORK = 'MSTest';\r\nexport const NUNITTESTFRAMEWORK = 'NUnit';\r\nexport const XUNITTESTFRAMEWORK = 'xUnit';\r\nexport const XapBondRelatedNamespace = 'using Microsoft.Bing.Xap.CodeGenCollections.Generic;';\r\n"]}
|
package/out/types/genResult.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"genResult.js","sourceRoot":"","sources":["../../src/types/genResult.ts"],"names":[],"mappings":"","sourcesContent":["import { BuildResult } from \"./buildResult\";\r\nimport { TestResult } from \"./testResult\";\r\n\r\nexport interface GenResult {\r\n testFilePath: string;\r\n testProjectPath: string;\r\n codeFilePath: string;\r\n success: boolean;\r\n buildResult?: BuildResult;\r\n testResult?: TestResult;\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"genResult.js","sourceRoot":"","sources":["../../src/types/genResult.ts"],"names":[],"mappings":"","sourcesContent":["import { BuildResult } from \"./buildResult\";\r\nimport { TestResult } from \"./testResult\";\r\n\r\nexport interface GenResult {\r\n testFilePath: string;\r\n testProjectPath: string;\r\n codeFilePath: string;\r\n success: boolean;\r\n buildResult?: BuildResult[];\r\n testResult?: TestResult;\r\n}\r\n"]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export declare function checkXapCodeInterface(codePath: string): boolean;
|
|
2
|
-
export declare function checkXapCode(
|
|
2
|
+
export declare function checkXapCode(sourceCodePath: string, sourceCode: string): boolean;
|
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.checkXapCodeInterface = checkXapCodeInterface;
|
|
37
37
|
exports.checkXapCode = checkXapCode;
|
|
38
38
|
const fs = __importStar(require("fs"));
|
|
39
|
+
const getCodeStructurePath_1 = require("./getCodeStructurePath");
|
|
39
40
|
const XapInterfaces = [
|
|
40
41
|
"IPlugin",
|
|
41
42
|
"IConditionPlugin",
|
|
@@ -53,7 +54,18 @@ function checkXapCodeInterface(codePath) {
|
|
|
53
54
|
return false;
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
|
-
function checkXapCode(
|
|
57
|
-
|
|
57
|
+
function checkXapCode(sourceCodePath, sourceCode) {
|
|
58
|
+
const csprojPath = (0, getCodeStructurePath_1.getSourceFileCsprojFilePath)(sourceCodePath);
|
|
59
|
+
if (!csprojPath || !fs.existsSync(csprojPath)) {
|
|
60
|
+
return sourceCode.includes('using Xap.PluginFramework;');
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
const csprojContent = fs.readFileSync(csprojPath, 'utf-8');
|
|
64
|
+
const xapProjectTypeRegex = /<XapProjectType>.*?<\/XapProjectType>/;
|
|
65
|
+
return xapProjectTypeRegex.test(csprojContent);
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
58
70
|
}
|
|
59
71
|
//# sourceMappingURL=checkXapCode.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkXapCode.js","sourceRoot":"","sources":["../../src/utils/checkXapCode.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"checkXapCode.js","sourceRoot":"","sources":["../../src/utils/checkXapCode.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAYA,sDAOC;AAED,oCAcC;AAnCD,uCAAyB;AACzB,iEAAqE;AAErE,MAAM,aAAa,GAAG;IAClB,SAAS;IACT,kBAAkB;IAClB,UAAU;IACV,aAAa;IACb,kBAAkB;IAClB,cAAc;CACjB,CAAC;AAEF,SAAgB,qBAAqB,CAAC,QAAgB;IAClD,IAAI,CAAC;QACD,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACnD,OAAO,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,KAAK,EAAE,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC;IACxG,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC;AAED,SAAgB,YAAY,CAAC,cAAsB,EAAE,UAAkB;IACnE,MAAM,UAAU,GAAG,IAAA,kDAA2B,EAAC,cAAc,CAAC,CAAC;IAE/D,IAAI,CAAC,UAAU,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5C,OAAO,UAAU,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC;IAC7D,CAAC;IAED,IAAI,CAAC;QACD,MAAM,aAAa,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC3D,MAAM,mBAAmB,GAAG,uCAAuC,CAAC;QACpE,OAAO,mBAAmB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACnD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC","sourcesContent":["import * as fs from 'fs';\r\nimport { getSourceFileCsprojFilePath } from './getCodeStructurePath';\r\n\r\nconst XapInterfaces = [\r\n \"IPlugin\",\r\n \"IConditionPlugin\",\r\n \"Workflow\",\r\n \"IExperiment\",\r\n \"IPluginDataStore\",\r\n \"IAsyncPlugin\"\r\n];\r\n\r\nexport function checkXapCodeInterface(codePath: string): boolean {\r\n try {\r\n const content = fs.readFileSync(codePath, 'utf-8');\r\n return XapInterfaces.some(iface => content.includes(`:${iface}`) || content.includes(`: ${iface}`));\r\n } catch (err) {\r\n return false;\r\n }\r\n}\r\n\r\nexport function checkXapCode(sourceCodePath: string, sourceCode: string): boolean {\r\n const csprojPath = getSourceFileCsprojFilePath(sourceCodePath);\r\n \r\n if (!csprojPath || !fs.existsSync(csprojPath)) {\r\n return sourceCode.includes('using Xap.PluginFramework;');\r\n }\r\n \r\n try {\r\n const csprojContent = fs.readFileSync(csprojPath, 'utf-8');\r\n const xapProjectTypeRegex = /<XapProjectType>.*?<\\/XapProjectType>/;\r\n return xapProjectTypeRegex.test(csprojContent);\r\n } catch (err) {\r\n return false;\r\n }\r\n}"]}
|
package/out/utils/fileUtils.d.ts
CHANGED
package/out/utils/fileUtils.js
CHANGED
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.writeTestCode = writeTestCode;
|
|
7
|
+
exports.readTestCode = readTestCode;
|
|
7
8
|
exports.deleteTestFileIfExists = deleteTestFileIfExists;
|
|
8
9
|
const fs_1 = __importDefault(require("fs"));
|
|
9
10
|
// split test file path detection out to a separate function
|
|
@@ -27,6 +28,18 @@ function writeTestCode(testCode, testFilePath) {
|
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
}
|
|
31
|
+
function readTestCode(testFilePath) {
|
|
32
|
+
try {
|
|
33
|
+
if (fs_1.default.existsSync(testFilePath)) {
|
|
34
|
+
return fs_1.default.readFileSync(testFilePath, 'utf8');
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
console.error(`Failed to read test code: ${error.message}`);
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
30
43
|
function deleteTestFileIfExists(testFilePath) {
|
|
31
44
|
if (fs_1.default.existsSync(testFilePath)) {
|
|
32
45
|
fs_1.default.unlink(testFilePath, (err) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fileUtils.js","sourceRoot":"","sources":["../../src/utils/fileUtils.ts"],"names":[],"mappings":";;;;;AAGA,sCAgBC;AAGD,wDAUC;
|
|
1
|
+
{"version":3,"file":"fileUtils.js","sourceRoot":"","sources":["../../src/utils/fileUtils.ts"],"names":[],"mappings":";;;;;AAGA,sCAgBC;AAED,oCAUC;AAGD,wDAUC;AA5CD,4CAAoB;AAEpB,4DAA4D;AAC5D,SAAgB,aAAa,CAAC,QAAgB,EAAE,YAAoB;IAChE,MAAM,aAAa,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IACjD,4CAA4C;IAC5C,IAAI,CAAC;QACD,YAAE,CAAC,aAAa,CAAC,YAAY,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;IAC1D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,8BAA8B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC7D,yCAAyC;QACzC,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC1B,OAAO,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACnE,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACjC,OAAO,CAAC,KAAK,CAAC,gEAAgE,YAAY,EAAE,CAAC,CAAC;QAClG,CAAC;aAAM,CAAC;YACJ,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QACnD,CAAC;IACL,CAAC;AACL,CAAC;AAED,SAAgB,YAAY,CAAC,YAAoB;IAC7C,IAAI,CAAC;QACD,IAAI,YAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAC9B,OAAO,YAAE,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QACjD,CAAC;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,6BAA6B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5D,OAAO,IAAI,CAAC;IAChB,CAAC;AACL,CAAC;AAGD,SAAgB,sBAAsB,CAAC,YAAoB;IACvD,IAAI,YAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9B,YAAE,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,GAAG,EAAE,EAAE;YAC5B,IAAI,GAAG,EAAE,CAAC;gBACN,OAAO,CAAC,KAAK,CAAC,+BAA+B,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YAChE,CAAC;iBAAM,CAAC;gBACJ,OAAO,CAAC,GAAG,CAAC,sBAAsB,YAAY,EAAE,CAAC,CAAC;YACtD,CAAC;QACL,CAAC,CAAC,CAAC;IACP,CAAC;AACL,CAAC","sourcesContent":["import fs from 'fs';\r\n\r\n// split test file path detection out to a separate function\r\nexport function writeTestCode(testCode: string, testFilePath: string) {\r\n const validTestCode = !!testCode ? testCode : ''; \r\n // Write the test code to the specified file\r\n try {\r\n fs.writeFileSync(testFilePath, validTestCode, 'utf8');\r\n } catch (error) {\r\n console.error(`Failed to write test code: ${error.message}`);\r\n // categorize the error based on its code\r\n if (error.code === 'EACCES') {\r\n console.error('can not write to the file, permission denied.');\r\n } else if (error.code === 'ENOENT') {\r\n console.error(`can not write to the file, file or directory does not exist: ${testFilePath}`);\r\n } else {\r\n console.error('unknown error:', error.message);\r\n }\r\n }\r\n}\r\n\r\nexport function readTestCode(testFilePath: string): string | null {\r\n try {\r\n if (fs.existsSync(testFilePath)) {\r\n return fs.readFileSync(testFilePath, 'utf8');\r\n }\r\n return null;\r\n } catch (error) {\r\n console.error(`Failed to read test code: ${error.message}`);\r\n return null;\r\n }\r\n}\r\n\r\n\r\nexport function deleteTestFileIfExists(testFilePath: string): void {\r\n if (fs.existsSync(testFilePath)) {\r\n fs.unlink(testFilePath, (err) => {\r\n if (err) {\r\n console.error(`Failed to delete test file: ${err.message}`);\r\n } else {\r\n console.log(`Deleted test file: ${testFilePath}`);\r\n }\r\n });\r\n }\r\n}"]}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
export declare function getSourceFileProjectDir(sourceCodePath: string): string;
|
|
2
2
|
export declare function getSourceFileCsprojFilePath(sourceCodePath: string): string;
|
|
3
3
|
export declare function getCodeRepoRoot(csFilePath: string): string;
|
|
4
|
+
/**
|
|
5
|
+
* Find the solution file (.sln) by searching upward from the source file path.
|
|
6
|
+
*/
|
|
7
|
+
export declare function findSolutionFile(sourceFilePath: string): string | null;
|
|
4
8
|
export declare function getAssemblyName(csprojPath: string): string;
|
|
5
9
|
export declare function getBuiltDllPath(csprojPath: string): string;
|
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.getSourceFileProjectDir = getSourceFileProjectDir;
|
|
37
37
|
exports.getSourceFileCsprojFilePath = getSourceFileCsprojFilePath;
|
|
38
38
|
exports.getCodeRepoRoot = getCodeRepoRoot;
|
|
39
|
+
exports.findSolutionFile = findSolutionFile;
|
|
39
40
|
exports.getAssemblyName = getAssemblyName;
|
|
40
41
|
exports.getBuiltDllPath = getBuiltDllPath;
|
|
41
42
|
const fs = __importStar(require("fs"));
|
|
@@ -97,6 +98,35 @@ function getCodeRepoRoot(csFilePath) {
|
|
|
97
98
|
console.log(`No .git folder found in the dir hierarchy of ${csFilePath}. Assuming root is ${rootDir}`);
|
|
98
99
|
return rootDir;
|
|
99
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Find the solution file (.sln) by searching upward from the source file path.
|
|
103
|
+
*/
|
|
104
|
+
function findSolutionFile(sourceFilePath) {
|
|
105
|
+
const repoRoot = getCodeRepoRoot(sourceFilePath);
|
|
106
|
+
let currentDir = path.dirname(sourceFilePath);
|
|
107
|
+
while (true) {
|
|
108
|
+
const rel = path.relative(repoRoot, currentDir);
|
|
109
|
+
if (rel.startsWith('..') || path.isAbsolute(rel)) {
|
|
110
|
+
break; // currentDir is outside repoRoot
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
const files = fs.readdirSync(currentDir);
|
|
114
|
+
const slnFiles = files.filter(file => file.toLowerCase().endsWith('.sln'));
|
|
115
|
+
if (slnFiles.length > 0) {
|
|
116
|
+
return path.join(currentDir, slnFiles[0]);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
// Skip directories we can't read
|
|
121
|
+
}
|
|
122
|
+
const parentDir = path.dirname(currentDir);
|
|
123
|
+
if (parentDir === currentDir) {
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
currentDir = parentDir;
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
100
130
|
// export function getTestProjectDll(testProjectPath: string) {
|
|
101
131
|
// const testProjectDir = path.dirname(testProjectPath);
|
|
102
132
|
// const testProjectName = path.basename(testProjectPath, '.csproj');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getCodeStructurePath.js","sourceRoot":"","sources":["../../src/utils/getCodeStructurePath.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\r\nimport * as path from 'path';\r\n\r\nimport { XMLParser } from 'fast-xml-parser';\r\n\r\nexport function getSourceFileProjectDir(sourceCodePath: string) {\r\n let currentDir = path.dirname(sourceCodePath);\r\n\r\n while (currentDir !== path.dirname(currentDir)) {\r\n const files = fs.readdirSync(currentDir);\r\n if (files.some(file => file.endsWith('.csproj'))) {\r\n return currentDir;\r\n }\r\n currentDir = path.dirname(currentDir);\r\n }\r\n\r\n // Check root directory\r\n const rootFiles = fs.readdirSync(currentDir);\r\n if (rootFiles.some(file => file.endsWith('.csproj'))) {\r\n return currentDir;\r\n }\r\n\r\n return null; // No .csproj file found\r\n}\r\n\r\nexport function getSourceFileCsprojFilePath(sourceCodePath: string) {\r\n let currentDir = path.dirname(sourceCodePath);\r\n\r\n while (currentDir !== path.dirname(currentDir)) {\r\n const files = fs.readdirSync(currentDir);\r\n const csprojFilePaths = files.filter(file => file.endsWith('.csproj'));\r\n if (csprojFilePaths?.length > 0) {\r\n return path.join(currentDir, csprojFilePaths[0]);\r\n }\r\n currentDir = path.dirname(currentDir);\r\n }\r\n\r\n // Check root directory\r\n const rootFiles = fs.readdirSync(currentDir);\r\n if (rootFiles.some(file => file.endsWith('.csproj'))) {\r\n return currentDir;\r\n }\r\n\r\n return null; // No .csproj file found\r\n}\r\n\r\n// export function getSourceFileProjectName(sourceCodePath: string) {\r\n// const projectPath = getSourceFileProjectPath(sourceCodePath);\r\n// if (!projectPath) {\r\n// console.warn(`No .csproj file found for ${sourceCodePath}`);\r\n// return null;\r\n// }\r\n\r\n// const projectName = path.basename(projectPath, '.csproj');\r\n// return projectName;\r\n// }\r\n\r\n// detect .git folder in the dir hierarchy of csFilePath, if exist, it's the code repo root\r\nexport function getCodeRepoRoot(csFilePath: string) {\r\n const rootDir = path.parse(csFilePath).root;\r\n let currentDir = path.dirname(csFilePath);;\r\n\r\n while (currentDir !== rootDir) {\r\n if (fs.existsSync(path.join(currentDir, \".git\"))) {\r\n return currentDir;\r\n }\r\n currentDir = path.dirname(currentDir);\r\n }\r\n\r\n console.log(`No .git folder found in the dir hierarchy of ${csFilePath}. Assuming root is ${rootDir}`);\r\n return rootDir;\r\n}\r\n\r\n// export function getTestProjectDll(testProjectPath: string) {\r\n// const testProjectDir = path.dirname(testProjectPath);\r\n// const testProjectName = path.basename(testProjectPath, '.csproj');\r\n// const dllName = `${testProjectName}.dll`;\r\n// const dllPath = path.join(testProjectDir, 'bin', 'Debug', dllName);\r\n// return dllPath;\r\n// }\r\n\r\n\r\nexport function getAssemblyName(csprojPath: string): string {\r\n const xmlContent = fs.readFileSync(csprojPath, \"utf-8\");\r\n const parser = new XMLParser();\r\n const parsed = parser.parse(xmlContent);\r\n\r\n const project = parsed.Project;\r\n if (!project) {\r\n throw new Error(\"can't parse .csproj 文件\");\r\n }\r\n\r\n const propertyGroups = Array.isArray(project.PropertyGroup)\r\n ? project.PropertyGroup\r\n : [project.PropertyGroup];\r\n\r\n for (const group of propertyGroups) {\r\n if (group.AssemblyName) {\r\n return group.AssemblyName;\r\n }\r\n }\r\n\r\n return path.basename(csprojPath, \".csproj\");\r\n}\r\n\r\nfunction getDllPath(outputDir: string, assemblyName: string): string {\r\n if (!fs.existsSync(outputDir)) {\r\n throw new Error(`The output dir doesn't exist: ${outputDir}`);\r\n }\r\n\r\n // xap dll path: \"D:\\code\\CS.Service.Fundamental\\SharedSegments\\SharedSegments\\SharedSegments.Tests\\bin\\Debug\\SharedSegments.Tests.dll\"\r\n const dllPath = path.join(outputDir, `${assemblyName}.dll`);\r\n if (fs.existsSync(dllPath)) {\r\n return dllPath;\r\n }\r\n\r\n // general dll path: \"D:\\code\\ai-dev-tools\\csharp-ut-copilot\\CSharpAnalyzer\\CSharpAnalyzer\\bin\\Debug\\net8.0\\CSharpAnalyzer.dll\"\r\n const subdirs = fs.readdirSync(outputDir).filter((f) =>\r\n fs.statSync(path.join(outputDir, f)).isDirectory()\r\n );\r\n\r\n for (const frameworkDir of subdirs) {\r\n const dllPath = path.join(outputDir, frameworkDir, `${assemblyName}.dll`);\r\n if (fs.existsSync(dllPath)) {\r\n return dllPath;\r\n }\r\n }\r\n\r\n throw new Error(`can't get dll file: ${assemblyName}.dll`);\r\n}\r\n\r\nexport function getBuiltDllPath(csprojPath: string): string {\r\n if (!fs.existsSync(csprojPath)) {\r\n throw new Error(`csproj doesn't exist: ${csprojPath}`);\r\n }\r\n\r\n const assemblyName = getAssemblyName(csprojPath);\r\n const projectDir = path.dirname(csprojPath);\r\n const outputBase = path.join(projectDir, \"bin\", \"Debug\");\r\n\r\n return getDllPath(outputBase, assemblyName);\r\n}\r\n\r\n\r\n// const dllPath = getBuiltDllPath(\"D:\\\\code\\\\CS.Service.Fundamental\\\\SharedSegments\\\\SharedSegments\\\\SharedSegments.Tests\\\\SharedSegments.Tests.csproj\");\r\n// console.log(`Test project DLL path: ${dllPath}`);"]}
|
|
1
|
+
{"version":3,"file":"getCodeStructurePath.js","sourceRoot":"","sources":["../../src/utils/getCodeStructurePath.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\r\nimport * as path from 'path';\r\n\r\nimport { XMLParser } from 'fast-xml-parser';\r\n\r\nexport function getSourceFileProjectDir(sourceCodePath: string) {\r\n let currentDir = path.dirname(sourceCodePath);\r\n\r\n while (currentDir !== path.dirname(currentDir)) {\r\n const files = fs.readdirSync(currentDir);\r\n if (files.some(file => file.endsWith('.csproj'))) {\r\n return currentDir;\r\n }\r\n currentDir = path.dirname(currentDir);\r\n }\r\n\r\n // Check root directory\r\n const rootFiles = fs.readdirSync(currentDir);\r\n if (rootFiles.some(file => file.endsWith('.csproj'))) {\r\n return currentDir;\r\n }\r\n\r\n return null; // No .csproj file found\r\n}\r\n\r\nexport function getSourceFileCsprojFilePath(sourceCodePath: string) {\r\n let currentDir = path.dirname(sourceCodePath);\r\n\r\n while (currentDir !== path.dirname(currentDir)) {\r\n const files = fs.readdirSync(currentDir);\r\n const csprojFilePaths = files.filter(file => file.endsWith('.csproj'));\r\n if (csprojFilePaths?.length > 0) {\r\n return path.join(currentDir, csprojFilePaths[0]);\r\n }\r\n currentDir = path.dirname(currentDir);\r\n }\r\n\r\n // Check root directory\r\n const rootFiles = fs.readdirSync(currentDir);\r\n if (rootFiles.some(file => file.endsWith('.csproj'))) {\r\n return currentDir;\r\n }\r\n\r\n return null; // No .csproj file found\r\n}\r\n\r\n// export function getSourceFileProjectName(sourceCodePath: string) {\r\n// const projectPath = getSourceFileProjectPath(sourceCodePath);\r\n// if (!projectPath) {\r\n// console.warn(`No .csproj file found for ${sourceCodePath}`);\r\n// return null;\r\n// }\r\n\r\n// const projectName = path.basename(projectPath, '.csproj');\r\n// return projectName;\r\n// }\r\n\r\n// detect .git folder in the dir hierarchy of csFilePath, if exist, it's the code repo root\r\nexport function getCodeRepoRoot(csFilePath: string) {\r\n const rootDir = path.parse(csFilePath).root;\r\n let currentDir = path.dirname(csFilePath);;\r\n\r\n while (currentDir !== rootDir) {\r\n if (fs.existsSync(path.join(currentDir, \".git\"))) {\r\n return currentDir;\r\n }\r\n currentDir = path.dirname(currentDir);\r\n }\r\n\r\n console.log(`No .git folder found in the dir hierarchy of ${csFilePath}. Assuming root is ${rootDir}`);\r\n return rootDir;\r\n}\r\n\r\n/**\r\n * Find the solution file (.sln) by searching upward from the source file path.\r\n */\r\nexport function findSolutionFile(sourceFilePath: string): string | null {\r\n const repoRoot = getCodeRepoRoot(sourceFilePath);\r\n let currentDir = path.dirname(sourceFilePath);\r\n\r\n while (true) {\r\n const rel = path.relative(repoRoot, currentDir);\r\n if (rel.startsWith('..') || path.isAbsolute(rel)) {\r\n break; // currentDir is outside repoRoot\r\n }\r\n try {\r\n const files = fs.readdirSync(currentDir);\r\n const slnFiles = files.filter(file => file.toLowerCase().endsWith('.sln'));\r\n if (slnFiles.length > 0) {\r\n return path.join(currentDir, slnFiles[0]);\r\n }\r\n } catch (error) {\r\n // Skip directories we can't read\r\n }\r\n \r\n const parentDir = path.dirname(currentDir);\r\n if (parentDir === currentDir) {\r\n break;\r\n }\r\n currentDir = parentDir;\r\n }\r\n\r\n return null;\r\n}\r\n\r\n// export function getTestProjectDll(testProjectPath: string) {\r\n// const testProjectDir = path.dirname(testProjectPath);\r\n// const testProjectName = path.basename(testProjectPath, '.csproj');\r\n// const dllName = `${testProjectName}.dll`;\r\n// const dllPath = path.join(testProjectDir, 'bin', 'Debug', dllName);\r\n// return dllPath;\r\n// }\r\n\r\n\r\nexport function getAssemblyName(csprojPath: string): string {\r\n const xmlContent = fs.readFileSync(csprojPath, \"utf-8\");\r\n const parser = new XMLParser();\r\n const parsed = parser.parse(xmlContent);\r\n\r\n const project = parsed.Project;\r\n if (!project) {\r\n throw new Error(\"can't parse .csproj 文件\");\r\n }\r\n\r\n const propertyGroups = Array.isArray(project.PropertyGroup)\r\n ? project.PropertyGroup\r\n : [project.PropertyGroup];\r\n\r\n for (const group of propertyGroups) {\r\n if (group.AssemblyName) {\r\n return group.AssemblyName;\r\n }\r\n }\r\n\r\n return path.basename(csprojPath, \".csproj\");\r\n}\r\n\r\nfunction getDllPath(outputDir: string, assemblyName: string): string {\r\n if (!fs.existsSync(outputDir)) {\r\n throw new Error(`The output dir doesn't exist: ${outputDir}`);\r\n }\r\n\r\n // xap dll path: \"D:\\code\\CS.Service.Fundamental\\SharedSegments\\SharedSegments\\SharedSegments.Tests\\bin\\Debug\\SharedSegments.Tests.dll\"\r\n const dllPath = path.join(outputDir, `${assemblyName}.dll`);\r\n if (fs.existsSync(dllPath)) {\r\n return dllPath;\r\n }\r\n\r\n // general dll path: \"D:\\code\\ai-dev-tools\\csharp-ut-copilot\\CSharpAnalyzer\\CSharpAnalyzer\\bin\\Debug\\net8.0\\CSharpAnalyzer.dll\"\r\n const subdirs = fs.readdirSync(outputDir).filter((f) =>\r\n fs.statSync(path.join(outputDir, f)).isDirectory()\r\n );\r\n\r\n for (const frameworkDir of subdirs) {\r\n const dllPath = path.join(outputDir, frameworkDir, `${assemblyName}.dll`);\r\n if (fs.existsSync(dllPath)) {\r\n return dllPath;\r\n }\r\n }\r\n\r\n throw new Error(`can't get dll file: ${assemblyName}.dll`);\r\n}\r\n\r\nexport function getBuiltDllPath(csprojPath: string): string {\r\n if (!fs.existsSync(csprojPath)) {\r\n throw new Error(`csproj doesn't exist: ${csprojPath}`);\r\n }\r\n\r\n const assemblyName = getAssemblyName(csprojPath);\r\n const projectDir = path.dirname(csprojPath);\r\n const outputBase = path.join(projectDir, \"bin\", \"Debug\");\r\n\r\n return getDllPath(outputBase, assemblyName);\r\n}\r\n\r\n\r\n// const dllPath = getBuiltDllPath(\"D:\\\\code\\\\CS.Service.Fundamental\\\\SharedSegments\\\\SharedSegments\\\\SharedSegments.Tests\\\\SharedSegments.Tests.csproj\");\r\n// console.log(`Test project DLL path: ${dllPath}`);"]}
|
|
@@ -1,12 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export declare function
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Check if a file path is a test file based on common naming conventions.
|
|
3
|
+
* Checks if the file name (without .cs extension) ends with test, tests, unittest, or unittests.
|
|
4
|
+
*/
|
|
5
|
+
export declare function isTestFile(filepath: string): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Determine the best test file path for a source file.
|
|
8
|
+
* This function only calculates the path, it does not create any directories.
|
|
9
|
+
*
|
|
10
|
+
* @param sourceCodePath - Path to the source file
|
|
11
|
+
* @param testCsprojPath - Path to the test project's csproj file (optional)
|
|
12
|
+
* @returns Object with testFilePath, testProjectPath, and testFileExist flag
|
|
13
|
+
*/
|
|
14
|
+
export declare function determineTestFilePath(sourceCodePath: string, testCsprojPath?: string): {
|
|
15
|
+
testFilePath: string | null;
|
|
16
|
+
testProjectPath: string | null;
|
|
17
|
+
testFileExist?: boolean;
|
|
8
18
|
};
|
|
9
|
-
export declare function getOrCreatTestFile(sourceCodePath: string, testFilePath: string,
|
|
19
|
+
export declare function getOrCreatTestFile(sourceCodePath: string, testFilePath: string, changedTestFiles?: string[]): {
|
|
10
20
|
testFilePath: string;
|
|
11
21
|
testProjectPath: any;
|
|
12
22
|
testFileExist: boolean;
|