Skip to content

Name analysis ​

Works out which names exist in a Questionnaire, which of them each expression can reference, and how they depend on each other. It also lists the form's linkIds and the expressions that refer to them. It runs once per Questionnaire, before the rules, and the rules read its answers.

A declaration introduces a name that other expressions reference as %name. It can be a named expression at a catalogued location, such as a variable or an itemPopulationContext, a launchContext on the root, or an extractAllocateId. A sourceQueries result is not a declaration: the software running the form supplies it, so it is a host variable, listed in the config or supplied by a plugin.

An expression can reference:

  • the declarations on its own element, on the items above it and on the root, the nearest one winning when names repeat;
  • the names FHIRPath, FHIR and SDC define, such as %resource, %context, %questionnaire and %qitem, and any name starting vs- or ext-;
  • the names a module's assembleContext lists;
  • the host variables: the config's hostVariables, and the names plugins supply through their hostVariables hook, such as the Smart Forms sourceQueries names. A declaration or an assembleContext name of the same name wins.

A host variable cannot be a name FHIRPath, FHIR or SDC defines: in the config it is a CONFIG_INVALID error, and from a plugin it is dropped. A plugin hook that fails stops the run with PLUGIN_CRASH.

An extraction expression sees only the extraction names; any other expression sees all the declarations except them. An uncatalogued expression gets no answer, because its scope is not known.

What it works outRead by
The declarations, in document ordersdc/duplicate-declaration, sdc/shadowed-declaration, sdc/reserved-name
The %name references of each FHIRPath expression, and the names available theresdc/undefined-variable
What each declaration's expression referencessdc/dependency-cycle, smart-forms/forward-variable-reference
Whether others reference each declaration: referenced, unreferenced, blocked or unknownsdc/unused-declaration, smart-forms/repeating-group-variable
Whether a FHIRPath expression reads its input other than its linkId, so it can give each repetition of a group a different valuesmart-forms/repeating-group-variable, smart-forms/forward-variable-reference
The form's linkIds, and the where(linkId = …) referencessdc/unresolved-linkid

When a question cannot be answered for certain, for example after a defineVariable with a computed name, the answer says so, and the rules stay silent rather than guess.

Schema ​

Plugin rules get the declarations, references, available variables, dependencies, uses and input reads through RuleContext, but not the linkId analysis. What a plugin can import describes it.

Code ​

In packages/core/src/analysis/:

  • document-analysis.ts: analyseDocument runs the steps below once per Questionnaire, and returns the DocumentAnalysis.
  • declarations.ts: findDeclarations lists the declarations; findAssembleContextNames lists a module's assembleContext names.
  • available-variables.ts: availableVariables gives the names available at each site, and the built-in names. definerOf says which specification defines a name; plugins can import it.
  • dependencies.ts: findDependencies records what each declaration references.
  • uses.ts: findUses records whether each declaration is referenced.
  • linkids.ts: findLinkIds lists the items' linkIds; findLinkIdReferencesAt gives the linkId references of each site.
  • run/host-variables.ts: suppliedHostVariables calls a plugin's hostVariables hook and checks its result; lint.ts adds the names to the config's before the analysis.

Expression discovery in the architecture map has the full scope rules.