Repository: aws-cloudformation/cfn-lint

Issue:
Support SAM `AWS::Serverless::Application` without triggering W3002
### Is this feature request related to a new rule or cfn-lint capabilities?

rules, New capability

### Describe the feature you'd like to request

This is similar to https://github.com/aws-cloudformation/cfn-lint/issues/2297. When using a SAM template and creating a resource of type `AWS::Serverless::Application`, the string placed in the [location](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-application.html#sam-application-location) property is allowed to be a local file. This _does_ necessitate the use of `sam deploy` or `sam package` (documented in the SAM spec), but that is the intended workflow. Is there a way to get cfn-lint to natively (without ignores) support this workflow? Or is this working as intended and the correct solution is to just ignore that check (W3002) on that resource?

### Describe the solution you'd like

cfn-lint should fully validate resources of type `AWS::Serverless::Application` with a local file in the `Location` property without ignores.

### Additional context

_No response_

### Is this something that you'd be interested in working on?

- [X] 👋 I may be able to implement this feature request

### Would this feature include a breaking change?

- [ ] ⚠️ This feature might incur a breaking change


Discussion:

Resolving patch:
diff --git a/src/cfnlint/rules/resources/properties/PropertiesTemplated.py b/src/cfnlint/rules/resources/properties/PropertiesTemplated.py
--- a/src/cfnlint/rules/resources/properties/PropertiesTemplated.py
+++ b/src/cfnlint/rules/resources/properties/PropertiesTemplated.py
@@ -60,6 +60,9 @@ def match_resource_properties(self, properties, resourcetype, path, cfn):
         """Check CloudFormation Properties"""
         matches = []
 
+        if cfn.has_serverless_transform():
+            return []
+
         for key in self.templated_exceptions.get(resourcetype, []):
             matches.extend(
                 cfn.check_value(
diff --git a/src/cfnlint/template/template.py b/src/cfnlint/template/template.py
--- a/src/cfnlint/template/template.py
+++ b/src/cfnlint/template/template.py
@@ -94,9 +94,6 @@ def build_graph(self):
 
     def has_language_extensions_transform(self):
         """Check if the template has language extensions transform declared"""
-        LOGGER.debug(
-            "Check if the template has language extensions transform declaration"
-        )
         lang_extensions_transform = "AWS::LanguageExtensions"
         transform_declaration = self.transform_pre["Transform"]
         transform_type = (
@@ -106,6 +103,17 @@ def has_language_extensions_transform(self):
         )
         return bool(lang_extensions_transform in transform_type)
 
+    def has_serverless_transform(self):
+        """Check if the template has SAM transform declared"""
+        lang_extensions_transform = "AWS::Serverless-2016-10-31"
+        transform_declaration = self.transform_pre["Transform"]
+        transform_type = (
+            transform_declaration
+            if isinstance(transform_declaration, list)
+            else [transform_declaration]
+        )
+        return bool(lang_extensions_transform in transform_type)
+
     def get_resources(self, resource_type=[]):
         """
         Get Resources


Test patch:
diff --git a/test/fixtures/templates/good/resources/properties/templated_code_sam.yaml b/test/fixtures/templates/good/resources/properties/templated_code_sam.yaml
new file mode 100644
--- /dev/null
+++ b/test/fixtures/templates/good/resources/properties/templated_code_sam.yaml
@@ -0,0 +1,6 @@
+Transform: AWS::Serverless-2016-10-31
+Resources:
+  Function:
+    Type: AWS::Serverless::Application
+    Properties:
+      Location: path/
diff --git a/test/unit/rules/resources/properties/test_properties_templated.py b/test/unit/rules/resources/properties/test_properties_templated.py
--- a/test/unit/rules/resources/properties/test_properties_templated.py
+++ b/test/unit/rules/resources/properties/test_properties_templated.py
@@ -18,7 +18,8 @@ def setUp(self):
         super(TestPropertiesTemplated, self).setUp()
         self.collection.register(PropertiesTemplated())
         self.success_templates = [
-            "test/fixtures/templates/good/resources/properties/templated_code.yaml"
+            "test/fixtures/templates/good/resources/properties/templated_code.yaml",
+            "test/fixtures/templates/good/resources/properties/templated_code_sam.yaml",
         ]
 
     def test_file_positive(self):