diff --git a/config/platforms.yml b/config/platforms.yml
new file mode 100644
index 0000000..ddd80a7
--- /dev/null
+++ b/config/platforms.yml
@@ -0,0 +1,56 @@
+platforms:
+ rules:
+ # Heroku: heroku.yml is 100% unique to Heroku (Docker-based deploys).
+ heroku-yml:
+ when: fs.fileExists("heroku.yml")
+ then: heroku
+ group: cloud
+ read_files: [Procfile, app.json, heroku.yml, runtime.txt, .python-version]
+
+ # Heroku: app.json with Heroku-specific keys (buildpacks, addons).
+ heroku-app-json:
+ when: >-
+ fs.fileExists("app.json")
+ && (fs.fileContains("app.json", '"buildpacks"')
+ || fs.fileContains("app.json", '"addons"'))
+ then: heroku
+ group: cloud
+ read_files: [Procfile, app.json, heroku.yml, runtime.txt, .python-version]
+
+ # Heroku: Procfile alone is ambiguous (Dokku, Railway, Foreman).
+ # maybe results are filtered from digest/CLI output.
+ heroku-procfile:
+ when: fs.fileExists("Procfile")
+ maybe: heroku
+ group: cloud
+ read_files: [Procfile, app.json, heroku.yml, runtime.txt, .python-version]
+
+ # Platform.sh: per-app config or unified config.
+ platformsh:
+ when: >-
+ fs.fileExists(".platform.app.yaml")
+ || fs.fileExists(".platform.app.yml")
+ || fs.fileExists(".platform/applications.yaml")
+ || fs.fileExists(".platform/applications.yml")
+ then: platformsh
+ group: cloud
+ read_files:
+ - .platform.app.yaml
+ - .platform.app.yml
+ - .platform/applications.yaml
+ - .platform/applications.yml
+ - .platform/services.yaml
+ - .platform/services.yml
+ - .platform/routes.yaml
+ - .platform/routes.yml
+
+ # Upsun: config in .upsun/ directory.
+ upsun:
+ when: >-
+ fs.glob(".upsun/*.yaml").size() > 0
+ || fs.glob(".upsun/*.yml").size() > 0
+ then: upsun
+ group: cloud
+ read_files:
+ - .upsun/config.yaml
+ - .upsun/config.yml
diff --git a/docs/functions.md b/docs/functions.md
index 0193491..a911e91 100644
--- a/docs/functions.md
+++ b/docs/functions.md
@@ -64,8 +64,8 @@ Query YAML bytes (e.g. file contents) using YQ (same syntax as JQ).
### `@in`
-* `@in(A, list(A))` -> `bool`
-* `@in(A, map(A, B))` -> `bool`
+* `@in(, list())` -> `bool`
+* `@in(, map(, ))` -> `bool`
### `@not_strictly_false`
@@ -73,14 +73,14 @@ Query YAML bytes (e.g. file contents) using YQ (same syntax as JQ).
### `@sortByAssociatedKeys`
-* `.@sortByAssociatedKeys(list(int))` -> `list(T)`
-* `.@sortByAssociatedKeys(list(uint))` -> `list(T)`
-* `.@sortByAssociatedKeys(list(double))` -> `list(T)`
-* `.@sortByAssociatedKeys(list(bool))` -> `list(T)`
-* `.@sortByAssociatedKeys(list(google.protobuf.Duration))` -> `list(T)`
-* `.@sortByAssociatedKeys(list(google.protobuf.Timestamp))` -> `list(T)`
-* `.@sortByAssociatedKeys(list(string))` -> `list(T)`
-* `.@sortByAssociatedKeys(list(bytes))` -> `list(T)`
+* `)>.@sortByAssociatedKeys(list(int))` -> `list()`
+* `)>.@sortByAssociatedKeys(list(uint))` -> `list()`
+* `)>.@sortByAssociatedKeys(list(double))` -> `list()`
+* `)>.@sortByAssociatedKeys(list(bool))` -> `list()`
+* `)>.@sortByAssociatedKeys(list(google.protobuf.Duration))` -> `list()`
+* `)>.@sortByAssociatedKeys(list(google.protobuf.Timestamp))` -> `list()`
+* `)>.@sortByAssociatedKeys(list(string))` -> `list()`
+* `)>.@sortByAssociatedKeys(list(bytes))` -> `list()`
### `bool`
@@ -102,7 +102,7 @@ Query YAML bytes (e.g. file contents) using YQ (same syntax as JQ).
### `distinct`
-* `.distinct()` -> `list(T)`
+* `)>.distinct()` -> `list()`
### `double`
@@ -119,7 +119,7 @@ Query YAML bytes (e.g. file contents) using YQ (same syntax as JQ).
### `dyn`
-* `dyn(A)` -> `dyn`
+* `dyn()` -> `dyn`
### `endsWith`
@@ -127,7 +127,7 @@ Query YAML bytes (e.g. file contents) using YQ (same syntax as JQ).
### `flatten`
-* `.flatten()` -> `list(T)`
+* `))>.flatten()` -> `list()`
* `.flatten(int)` -> `list(dyn)`
### `format`
@@ -190,8 +190,8 @@ Query YAML bytes (e.g. file contents) using YQ (same syntax as JQ).
### `in`
-* `in(A, list(A))` -> `bool`
-* `in(A, map(A, B))` -> `bool`
+* `in(, list())` -> `bool`
+* `in(, map(, ))` -> `bool`
### `indexOf`
@@ -237,23 +237,23 @@ Query YAML bytes (e.g. file contents) using YQ (same syntax as JQ).
### `reverse`
-* `.reverse()` -> `list(T)`
+* `)>.reverse()` -> `list()`
* `.reverse()` -> `string`
### `size`
* `size(bytes)` -> `int`
* `.size()` -> `int`
-* `size(list(A))` -> `int`
-* `.size()` -> `int`
-* `size(map(A, B))` -> `int`
-* `