The workspace structure
The poly tool gives us access to the data structure that represents the workspace,
which is the same structure that all the poly commands operate on.
Here we will use the output from the example in the documentation.
To list all the keys at the root, execute poly ws get:keys from the examples/doc-example directory:
[:bases
:components
:changes
:interfaces
:messages
:name
:old
:paths
:projects
:settings
:user-input
:version
:ws-dir
:ws-local-dir
:ws-reader]
Let's go through all the keys.
bases
poly ws get:bases:user-api
{:interface-deps {:src ["user"], :test []},
:lib-deps {:src {"slacker/slacker" {:size 28408,
:type "maven",
:version "0.17.0"}}},
:lib-imports {:src ["se.example.user-api.api" "slacker.server"],
:test ["clojure.test" "se.example.user-api.core"]},
:lines-of-code {:src 13, :test 6},
:name "user-api",
:namespaces {:src [{:file-path "/Users/joakimtengstrand/source/polylith/examples/doc-example/bases/user-api/src/se/example/user_api/core.clj",
:imports ["se.example.user-api.api" "slacker.server"],
:name "core",
:namespace "se.example.user-api.core"}
{:file-path "/Users/joakimtengstrand/source/polylith/examples/doc-example/bases/user-api/src/se/example/user_api/api.clj",
:imports ["se.example.user.interface"],
:name "api",
:namespace "se.example.user-api.api"}],
:test [{:file-path "/Users/joakimtengstrand/source/polylith/examples/doc-example/bases/user-api/test/se/example/user_api/core_test.clj",
:imports ["clojure.test" "se.example.user-api.core"],
:name "core-test",
:namespace "se.example.user-api.core-test"}]},
:paths {:src ["src" "resources"], :test ["test"]},
:type "base"}
:interface-depsLists the interfaces each base depens on. Here it depends on theuserinterface from thesrccontext. This is because these.example.user-api.apinamespace importsse.example.user.interface. No interfaces are imported from thetestcontext in this example.:lib-depsLists the library dependencies the base depends on, defined in the:depskey in itsdeps.ednfile for thesrccontext, and the:aliases > :test > :extra-depsfor thetestcontext. The:sizeis in bytes.:lib-importsThe name is a bit misleading as internal namespaces for the base is also included.srcLists all imports from thesrccontext except component interfaces.testLists all imports from thetestcontext except component interfaces.
:lines-of-codeTotal number of lines of code for this base (all namespaces included).:nameThen name of the directory for this base under thebasesdirectory.:namespaces:srcLists all the namespaces that live under thesrcdirectory.:file-pathThe absolute path to the namespace.:importsLists all its namespaces.:nameThe name of the namespace where top namespace + base name (se.example+user-apiin thie case) are skipped away.namespaceThe full name of the namespace.
:testLists all the namespaces that live under thetestdirectory.
:pathsThe paths that are specified in itsdeps.ednfile (pathsforsrcandresourcespaths +aliases > :test > :extra-pathsfortestpaths).:typeSet to "base".
components
poly ws get:components:user
{:interface {:definitions [{:name "hello",
:parameters [{:name "name"}],
:type "function"}],
:name "user"},
:interface-deps {:src [], :test []},
:lib-deps {},
:lib-imports {:test ["clojure.test"]},
:lines-of-code {:src 9, :test 7},
:name "user",
:namespaces {:src [{:file-path "/Users/joakimtengstrand/source/polylith/examples/doc-example/components/user/src/se/example/user/interface.clj",
:imports ["se.example.user.core"],
:name "interface",
:namespace "se.example.user.interface"}
{:file-path "/Users/joakimtengstrand/source/polylith/examples/doc-example/components/user/src/se/example/user/core.clj",
:imports [],
:name "core",
:namespace "se.example.user.core"}],
:test [{:file-path "/Users/joakimtengstrand/source/polylith/examples/doc-example/components/user/test/se/example/user/interface_test.clj",
:imports ["clojure.test" "se.example.user.interface"],
:name "interface-test",
:namespace "se.example.user.interface-test"}]},
:paths {:src ["src" "resources"], :test ["test"]},
:type "component"}
Component keys are the same as for the base plus the :interfaces key:
:interface:definitionsLists all publicdef,defnanddefmacrodefinitions in the interface namespace. If a type hint is given, then:typewill also be set and be part of the contract.
:interface-depsLists the interfaces each component depens on. This component doesn't depend on any other interface.:lib-depsLists the library dependencies the component depends on, defined in the:depskey in itsdeps.ednfile for thesrccontext, and the:aliases > :test > :extra-depsfor thetestcontext.:lib-importsLists all imports except component interfaces. The name is a bit misleading as internal namespaces for the component is also included.:lines-of-codeTotal number of lines of code for this compoponent (all namespaces included).:nameThen name of the directory for this component under thecomponentsdirectory.:namespaces:srcLists all the namespaces that live under thesrcdirectory.:file-pathThe absolute path to the namespace.:importsLists all its namespaces.:nameThe name of the namespace where top namespace + component name (se.example+userin thie case) are skipped away.namespaceThe full name of the namespace.
:testLists all the namespaces that live under thetestdirectory.
:pathsThe paths that are specified in itsdeps.ednfile (pathsforsrcandresourcespaths +aliases > :test > :extra-pathsfortestpaths).:typeSet to "component".
changes
poly ws get:changes since:b339c35
{:changed-bases ["cli" "user-api"],
:changed-components ["user" "user-remote"],
:changed-files ["bases/cli/deps.edn"
"bases/cli/resources/cli/.keep"
"bases/cli/src/se/example/cli/core.clj"
"bases/cli/test/se/example/cli/core_test.clj"
"bases/user-api/deps.edn"
"bases/user-api/resources/user-api/.keep"
"bases/user-api/src/se/example/user_api/api.clj"
"bases/user-api/src/se/example/user_api/core.clj"
"bases/user-api/test/se/example/user_api/core_test.clj"
"components/user-remote/deps.edn"
"components/user-remote/resources/user-remote/.keep"
"components/user-remote/src/se/example/user/core.clj"
"components/user-remote/src/se/example/user/interface.clj"
"components/user-remote/test/se/example/user/interface_test.clj"
"components/user/deps.edn"
"components/user/resources/user/.keep"
"components/user/src/se/example/user/core.clj"
"components/user/src/se/example/user/interface.clj"
"components/user/test/se/example/user/interface_test.clj"
"deps.edn"
"development/src/dev/lisa.clj"
"projects/command-line/deps.edn"
"projects/command-line/test/project/command_line/dummy_test.clj"
"projects/user-service/deps.edn"
"readme.txt"
"scripts/build-cli-uberjar.sh"
"scripts/build-uberjar.sh"
"scripts/build-user-service-uberjar.sh"
"workspace.edn"],
:changed-or-affected-projects ["command-line" "development" "user-service"],
:changed-projects ["command-line" "development" "user-service"],
:git-diff-command "git diff b339c35 --name-only",
:project-to-bricks-to-test {"command-line" ["cli" "user-remote"],
"development" [],
"user-service" ["user" "user-api"]},
:project-to-indirect-changes {"command-line" {:src [], :test []},
"development" {:src [], :test []},
"user-service" {:src [], :test []}},
:project-to-projects-to-test {"command-line" [],
"development" [],
"user-service" []},
:since "b339c35",
:since-sha "b339c35"}
:changed-basesLists the changed bases since the shab339c35(or last stable point in time if:sinceis not given).:changed-componentsLists the changed components since the shab339c35(or last stable point in time if:sinceis not given).:changed-filesThe same list that is returned bypoly diff since:b339c35. The keys:changed-bases,:changed-componentsand:changed-projectsare calculated from this list.:changed-or-affected-projectsLists the projects that are directly changed, e.g. itsdeps.ednfile, or indirectly changed, e.g. if one of the bricks it incudes are changed.:changed-projectsLists the changed projects since the shab339c35(or last stable point in time if:sinceis not given).:git-diff-commandThe git command that was executed to calculate the:changed-fileslist.:project-to-bricks-to-testA map that stores project names with a list of the bricks to test from that project if executing thetestcommand.:project-to-indirect-changesA map that stores project names with a list of the bricks that are indirectly changed (directly changed bricks excluded). E.g. if componentsaandbare included in the project, andahas not changed, butbhas changed andausesb, thenbwill be included in the list.:project-to-projects-to-testA map that stores project names with a list of projects to test from that project if executing thetestcommand.:sinceSet to "stable" ifsince:SINCEis not given.:since-shaThe full sha ifsince:SINCEwas not given, e.g.b339c358079fa36ca20ed0163708ba010a0ffd4c.:since-tagThe name of the tag, e.g.v0.1.0-alpha9ifsince:releasewas given.
interfaces
poly ws get:interfaces:user
{:definitions [{:name "hello",
:parameters [{:name "name"}],
:type "function"}],
:implementing-components ["user" "user-remote"],
:name "user",
:type "interface"}
:definitionsA list of the publicdef,defnanddefmacrodefinitions that are part of the interface.:namethe name of thedef,defnordefmacrodefinition. If it's a multi arity function or macro, then each arity will stored separately.:parametersSet for functions and macros. Specifies the function/macro parameters::nameThe name of the parameter.:typeIf a type hint, e.g.^Stringis given then this attribute is set.
:typeSet todata,functionormacro.
:nameThe name of the interface. In this case the bricksuseranduser-remoteshare the sameuserinterface and live in these.example.user.interfacenamespace.:typeSet to "interface".
messages
poly ws get:messages
[{:code 103,
:message "Missing definitions in user's interface: hello[name]",
:colorized-message "Missing definitions in user's interface: hello[name]",
:components ["user"],
:type "error"}]
To trigger this error, we commented out the hello function from the user component interface.
:codeThe code of the error or warning. To get a full list of existing codes, executepoly help check.:messageThe error message.:colorized-messageThe error message using colors so the text can be printed in color.:componentsEach error message can have extra keys/information, like affected components as in this case.typeSet to "error" or "warning".
name
poly ws get:name
doc-example
The name of the workspace directory.
old
poly ws get:old ws-file:ws.edn
{:user-input {:args ["ws" "out:ws.edn"],
:cmd "ws",
:is-all false,
:is-dev false,
:is-latest-sha false,
:is-no-exit false,
:is-run-all-brick-tests false,
:is-run-project-tests false,
:is-search-for-ws-dir false,
:is-show-brick false,
:is-show-loc false,
:is-show-project false,
:is-show-resources false,
:is-show-workspace false,
:is-verbose false,
:out "ws.edn",
:selected-profiles #{},
:selected-projects #{},
:unnamed-args []}}
If the workspace is loaded using ws-file:WS-FILE then the :old key is populated.
user-inputThe user input from the originalwsfile.:active-profilesIf any profiles are given, then this key is added with the value of:active-profilestaken from the:settingskey from the originalwsfile.
paths
poly ws get:paths
{:existing ["bases/cli/resources"
"bases/cli/src"
"bases/cli/test"
"bases/user-api/resources"
"bases/user-api/src"
"bases/user-api/test"
"components/user-remote/resources"
"components/user-remote/src"
"components/user-remote/test"
"components/user/resources"
"components/user/src"
"components/user/test"
"development/src"
"projects/command-line/test"],
:on-disk ["bases/cli/resources"
"bases/cli/src"
"bases/cli/test"
"bases/user-api/resources"
"bases/user-api/src"
"bases/user-api/test"
"components/user-remote/resources"
"components/user-remote/src"
"components/user-remote/test"
"components/user/resources"
"components/user/src"
"components/user/test"
"projects/command-line/test"],
:missing []}
:existingAll existing paths in the workspace that are used in bricks, projects and profiles.:on-diskAll paths to directories within the workspace.missingAll missing paths in the workspace that are used in bricks, projects and profiles but does not exist on disk.
projects
poly ws get:projects:user-service
{:alias "user-s",
:base-names {:src ["user-api"], :test ["user-api"]},
:component-names {:src ["user"], :test ["user"]},
:config-filename "/Users/joakimtengstrand/source/polylith/examples/doc-example/projects/user-service/deps.edn",
:deps {"user" {:src {}, :test {}},
"user-api" {:src {:direct ["user-remote"]},
:test {:direct ["user-remote"]}}},
:is-dev false,
:is-run-tests true,
:lib-deps {:src {"org.apache.logging.log4j/log4j-core" {:size 1714164,
:type "maven",
:version "2.13.3"},
"org.apache.logging.log4j/log4j-slf4j-impl" {:size 23590,
:type "maven",
:version "2.13.3"},
"org.clojure/clojure" {:size 3914649,
:type "maven",
:version "1.10.3"},
"org.clojure/tools.deps"{:size 60953,
:type "maven",
:version "0.12.1003"},
"slacker/slacker" {:size 28408,
:type "maven",
:version "0.17.0"}}},
:lib-imports {:src ["se.example.user-api.api" "slacker.server"],
:test ["clojure.test" "se.example.user-api.core"]},
:lines-of-code {:src 0, :test 0, :total {:src 44, :test 26}},
:maven-repos {"central" {:url "https://repo1.maven.org/maven2/"},
"clojars" {:url "https://repo.clojars.org/"}},
:name "user-service",
:namespaces {},
:paths {:src ["bases/user-api/resources"
"bases/user-api/src"
"components/user/resources"
"components/user/src"],
:test ["bases/user-api/test" "components/user/test"]},
:project-dir "/Users/joakimtengstrand/source/polylith/examples/doc-example/projects/user-service",
:type "project"}
:aliasThe alias that is specified in:projectsinworkspace.ednfor this project.:base-names:srcThe bases that are included in the project for thesrccontext, either as paths or included as:local/root.:testThe bases that are included in the project for thetestcontext, either as paths or included as:local/root.
:component-names:srcThe components that are included in the project for thesrccontext, either as paths or included as:local/root.:testThe components that are included in the project for thetestcontext, either as paths or included as:local/root.
:config-filenameThe absolute path to thedeps.ednconfig file.:depsA map that stores brick names with a list with the interfaces each brick uses.:is-devSet totruefor thedevelopmentproject.:is-run-testsSet totrueif the project is relevant for running tests. Thedevelopmentproject is not included by default (and therefore set tofalse) but can be added by passing in:devor by giving it asprojects:devorprojects:development. This flag is also affected by passing in:alland:all-bricks.:lib-deps:srcStores a map with the libraries that are used in the project for thesrccontext.:sizeThe size of this library in bytes.:typeThe type of the library,maven,localorgit(:mvn/version,:local/rootand:git/url).:versionThe library version:- if type is
maventhen version is set to groupId/artifactId. - if type is
localthen version is set to-. - if type is
gitthen version is set to the first seven characters in thesha.
- if type is
:testStores a map with the libraries that are used in the project for thetestcontext.
:lib-importssrcAll:lib-importstaken from the bricks that are included in this project for thesrccontext.testAll:lib-importstaken from the bricks that are included in this project for thetestcontext.
:lines-of-code:srcNumber of lines of code living in the project'ssrcdirectory.:testNumber of lines of code living in the project'stestdirectory.:totalTotal number of lines of code for all the bricks that are included in this project.
:maven-reposThe maven repos that are used by this project. If:mvn/reposis specified by a brick that is included in this project, then it will automatically turn up in this list.:nameThe name of the project directory under theprojectsdirectory.:namespacesI the project has atestdirectory (and/or asrcdirectory, but they are discouraged to use for projects) then the included namespaces are listed here.:paths:srcLists the paths that are either explicitly defined as paths or implicitly defined as:local/rootbricks, for thesrccontext.:testLists the paths that are either explicitly defined as paths or implicitly defined as:local/rootbricks, for thetestcontext.
:project-dirThe absolute path to the project directory.:typeSet to "project".
settings
poly ws get:settings
{:active-profiles #{"default"},
:color-mode "dark",
:compact-views #{},
:default-profile-name "default",
:empty-character ".",
:interface-ns "interface",
:m2-dir "/Users/joakimtengstrand/.m2",
:profile-to-settings {"default" {:base-names [],
:component-names ["user"],
:lib-deps {},
:paths ["components/user/src"
"components/user/resources"
"components/user/test"],
:project-names []},
"remote" {:base-names [],
:component-names ["user-remote"],
:lib-deps {},
:paths ["components/user-remote/src"
"components/user-remote/resources"
"components/user-remote/test"],
:project-names []}},
:projects {"command-line" {:alias "cl"},
"development" {:alias "dev"},
"user-service" {:alias "user-s"}},
:tag-patterns {:release "v[0-9]*", :stable "stable-*"},
:thousand-separator ",",
:top-namespace "se.example",
:user-config-filename "/Users/joakimtengstrand/.config/polylith/config.edn",
:user-home "/Users/joakimtengstrand",
:vcs {:auto-add true,
:branch "master",
:git-root "/Users/joakimtengstrand/source/polylith",
:name "git",
:polylith {:branch "master",
:repo "https://github.com/polyfy/polylith.git"},
:stable-since {:sha "f7e8cd7fe83f6d2fdfdedda35fed5806ac418964",
:tag "stable-jote"}}}
:active-profilesIf any profiles are defined in./deps.ednthen the active profiles(s) are listed here.:color-modeThe color mode specified in~/.config/polylith/config.edn.:compact-viewsThe set of views that should be shown in a more compact way, specified inworkspace.edn.:default-profile-nameThe name of the default profile name, specified inworkspace.edn.:empty-characterThe character used to represent empty space in ouput from e.g. thelibscommand, specified inworkspace.edn.:interface-nsThe name of the namespace/package that are used to represent interfaces, specified inworkspace.edn.:m2-dirMaven user root directory. Set to "~/.m2" by default, but can be overridden in~/.config/polylith/config.edn.:profile-to-settingsA map with profile name as key and profile definition as value, specified as aliases starting with a+in./deps.edn::base-namesThe bases that are referenced from the specified paths.:component-namesThe components that are referenced from the specified paths.:lib-depsThe library dependencies specified by the key:extra-deps.:pathsThe paths specified by the key:extra-paths.:project-namesThe projects that are referenced from the specified paths.
:projectsA map with extra information per project, specified inworkspace.edn.:aliasThe alias for a project, used by e.g. theinfocommand.:test:includeSpecifies which bricks should be included when running thetestcommand. Empty if no bricks, missing if all bricks.
:tag-patternsThe tag patterns that are specified inworkspace.edn.:thousand-separatorUsed by numbers >= 1000 (e.g. the KB column in thelibscommand) specified in~/.config/polylith/config.edn.:top-namespaceThe top namespace for the workspace, specified inworkspace.edn.:user-config-filenameThe full path to the user config name.:user-homeThe user home, specified by theuser.homeenvironment variable.:vcs:auto-addSet totrueif files and directories created by thecreatecommand should be automatically added togit. Specified inworkspace.edn.:branchThe name of the git branch.:git-rootThe root of the git repository.:nameSet to "git".:polylith:branchSetmasterorBRANCHifbranch:BRANCHis given. The branch is used when calculating the latestshain./deps.ednfor the key:aliases > :poly > :extra-deps > sha.:latest-shaIf:latest-shais given, then the latestshafrom the Polylith repo (https://github.com/polyfy/polylith.git) is retrieved.:repoSet to "https://github.com/polyfy/polylith.git".
:stable-since:shaThe latest stable point in time.:tagThetagfor the latest stable point in time (if given).
user-input
poly ws get:user-input
{:args ["ws" "get:user-input"],
:cmd "ws",
:get "user-input",
:is-all false,
:is-dev false,
:is-latest-sha false,
:is-no-exit false,
:is-run-all-brick-tests false,
:is-run-project-tests false,
:is-search-for-ws-dir false,
:is-show-brick false,
:is-show-loc false,
:is-show-project false,
:is-show-resources false,
:is-show-workspace false,
:is-verbose false,
:selected-profiles #{},
:selected-projects #{},
:unnamed-args []}
:argsThe arguments to thepolytool where the first argument is the command.:cmdThe first argument to thepolycommand.:getTheARGSofget:ARGSif given.:is-allSet totrueif:allis given.:is-devSet totrueif:devis given.:is-latest-shaSet totrueif:latest-shais given.:is-no-exitSet totrueif:no-exitis given. This will prevent thepolycommand from exiting withSystem/exit.:is-run-all-brick-testsSet totrueif:allor:all-bricksare given.:is-run-project-testsSet totrueif:allor:projectare given.:is-shellSet totrueif a shell has been started with theshellcommand.:is-search-for-ws-dirSet totrueif::is given.:is-show-brickSet totrueif:brickis given. Used bypoly help deps :brickto show help for thedepscommand whenbrick:BRICKis given.:is-show-locSet totrueif:locis given. If given, then theinfocommand will show the number of lines of code.:is-show-projectSet totrueif:projectis given. Used bypoly help deps :projectto show help for thedepscommand whenproject:PROJECTis given.:is-show-resourcesSet totrueif:ror:resourcesis given. This will tell theinfocommand to show therstatus flag.:is-show-workspaceSet totrueif:workspaceis given. Used bypoly help deps :workspaceto show help for thedepscommand whenworkspace:WORKSPACEis given.:is-verboseExperimental at the moment. Can be used on combination with thetestcommand to show extra information.:selected-profilesA list with the passed in profiles, e.g.["defult" "extra"]ifpoly info +default +extrais executed.:selected-projectsThe list of projects given byproject:PROJECTand/or:dev(handled as "dev" if given).:unnamed-argsAll given arguments that don't contain a:and is not used by the . So if we typepoly ws get:user-input:unnamed-args missing xx:123it will return["missing"]but notxx.
There are a few more user input parameters that are mainly useful if you are a maintainer of the Polylith codebase itself:
:is-compactSet totrueif:compactis given. Used in combination with thelibsanddepscommands.:fake-shaSet toc91fdadiffake-sha:c91fdadis given. Used to set the "stable since" sha for the output from thelibscommand.:is-no-changesSet totrueif:no-changesis given. Used to fake that no changes have been made since the last stable point in time.:is-no-exitSet totrueif:no-exitis given. Tells thepolycommand to not exit withSystem/exit.:replaceSet to e.g.[{:from "/Users/joakimtengstrand", :to "my-home"}]ifreplace:$HOME:my-homeis given. It will replace this text too, so the output will actually be[{:from "my-home", :to "my-home"}]which is the behaviour we want (the whole idea with thereplaceparameter is to get the same output every time).
version
poly ws get:version
{:release {:date "2021-07-27",
:major 0,
:minor 2,
:patch 0,
:revision "alpha10.issue66.22"},
:name "0.2.0.alpha10.issue66.22",
:ws {:breaking 1,
:non-breaking 0,
:type :toolsdeps2}}
:release:dateThe date of the release in the formatyyyy-mm-dd.:majorThe major version, set to zero.:minorIncreased by one if any breaking changes.:patchIncreased by one for each release within a givenmajor.minor.:revisionWhat comes aftermajor.minor.path.:nameThe full name of the release.
:wsVersioning of the internalwsformat, returned bypoly ws.:breakingIncreased by one if introducing a non backwards compatible change of thewsformat. The goal is that1is the last breaking change.:non-breakingIncreased by one when a non breaking change is added to thewsformat.:typeSet to:toolsdeps1if a workspace created byv0.1.0-alpha9or earlier. Set to:toolsdeps2if a workspace created byv0.2.0-alpha10or later.
If the workspace has the old :toolsdeps1 format (created by v0.1.0-alpha9 or earlier)
then it will be transformed to the latest format and the :from key is added:
{:from {:ws {:type :toolsdeps1}
...}
:from:ws:typeSet to ":toolsdeps1"
If the workspace is read from a ws file that was created by v0.1.0-alpha9 or earlier,
then the ws structure is transformed to the new format and the :from key is added:
poly ws get:version ws-file:ws1.edn
{:from {:release-name "0.1.0-alpha9",
:ws {:breaking 0,
:non-breaking 0,
:type :toolsdeps1}}
...
:from:release-nameThe version of thepolytool from which thiswsfile was created.:ws:breakingThe breaking version of the originalwsformat.:non-breakingThe non-breaking version of the originalwsformat.:typeThe type of the originalwsfile.
ws-dir
poly ws get:ws-dir
"/Users/joakimtengstrand/source/polylith/examples/doc-example"
The absolute path of the workspace directory.
ws-local-dir
poly ws get:ws-local-dir
"examples/doc-example"
If the workspace lives at the same level as the git root, which is the case if we create
a workspace with poly create workspace ..., then this attribute is not set.
If the workspace lives inside the git root as a directory or sub directory, then it
is set to the relative path to the git root.
ws-reader
poly ws get:ws-reader
{:file-extensions ["clj" "cljc"],
:language "Clojure",
:name "polylith-clj",
:project-url "https://github.com/polyfy/polylith",
:type-position "postfix"}
This structure explains different aspects of the tool that created this ws structure
(the poly tool in this case) and the idea is that new tooling could support the
ws format and populate this structure so that it can be used by external tooling.
:file-extensionsLists the supported file extensions.:languageThe name of the supported language.:nameThe name of the workspace reader.:project-urlThe url to the workspace reader tool.:type-positionSet topostfixbecause types (type hints) come before the arguments, in Clojure, e.g.^String arg. In some other languages like Scala, the types come after the arguments.