en-US/about_CompleterActions_Migration.help.txt

TOPIC
    about_CompleterActions_Migration

SYNOPSIS
    Explains what changed in CompleterActions 2.0.0 and how to move a
    profile or script from the 1.x commands to the new ones: the renamed
    commands and their aliases, the explicit target contract, the single
    -State filter and the new Discovered state, the promised sort order, and
    the typed output records.

LONG DESCRIPTION

    CompleterActions 2.0.0 makes every incompatible change of the 2.x line
    at once, so there is exactly one migration to make. Five things changed:

    - The three commands with the CompleterRegistration noun were renamed to
      Get-Completer, Register-Completer, and Unregister-Completer. The old
      names keep working as aliases until 3.0 and warn once per process.
    - Targets are explicit. A hand-typed key string such as 'git' or
      'git:checkout' is no longer accepted as input; a target is named with
      -CommandName plus -Native or -ParameterName, or described by a record
      that carries IsNative. Keys are output-only identifiers.
    - The -ManagedOnly and -DiscoveredOnly switches were replaced by one
      -State parameter, and a runtime registration that no managed record
      describes now reports State 'Discovered' instead of 'Active'.
    - Get-Completer sorts its output by CompleterType, CommandName, and
      ParameterName before paging.
    - Registration, import, finding, and completion-match records are
      PowerShell classes, and State is a real enum.

    The sections below show each change with the 1.x call on the left of a
    "before" block and the 2.0 call in the "after" block, followed by a
    checklist for a profile. Import-CompleterScript, Import-CompleterSet,
    Export-CompleterSet, Test-CompleterScript, and Test-CompleterRegistration
    keep their names; the target contract and typed output apply to them too.

COMMAND NAMES

    | 1.x | 2.0 |
    | -------------------------------- | ---------------------- |
    | Get-CompleterRegistration | Get-Completer |
    | Register-CompleterRegistration | Register-Completer |
    | Unregister-CompleterRegistration | Unregister-Completer |

    Before:

        Import-CompleterScript -Path .\git_completer.ps1 |
            Register-CompleterRegistration
        Get-CompleterRegistration -CommandName git -Native
        Unregister-CompleterRegistration -CommandName git -Native

    After:

        Import-CompleterScript -Path .\git_completer.ps1 |
            Register-Completer
        Get-Completer -CommandName git -Native
        Unregister-Completer -CommandName git -Native

    Each old name is an exported alias of a legacy wrapper function
    (Get-CompleterRegistrationLegacy, Register-CompleterRegistrationLegacy,
    Unregister-CompleterRegistrationLegacy) that forwards every parameter,
    pipeline input, -WhatIf, and -Confirm to the new command. The wrappers
    are exported because an exported alias whose target is not exported
    fails at the call site, so `Get-Command -Module CompleterActions` lists
    thirteen functions (eleven in 2.0.0) and three aliases. `Get-Help` on an
    old name shows the new command's help.

    The first call to each old name in a process writes one warning:

        WARNING: Get-CompleterRegistration is deprecated and will be removed
        in 3.0; use Get-Completer instead. See
        about_CompleterActions_Migration.

    Later calls in the same process are silent, so a profile that calls an
    old name many times warns once. The old names and the wrappers are
    removed in 3.0.

TARGETS ARE EXPLICIT

    In 1.x a key string could name a target: a key without a colon was a
    native command, 'Command:Parameter' was a parameter completer, and a
    path separator after the last colon turned it back into a native command
    path. That inference is gone. Get, Register, Unregister, and
    Test-CompleterRegistration no longer have a -Key parameter, and an input
    object that carries only a Key, RegistrationKey, or RuntimeKey is
    rejected.

    Before:

        Get-CompleterRegistration -Key 'git'
        Get-CompleterRegistration -Key 'git:checkout', 'git:branch'
        Unregister-CompleterRegistration -Key 'C:\tools\example.exe'
        [pscustomobject] @{ RegistrationKey = 'git:checkout' } |
            Get-CompleterRegistration

    After:

        Get-Completer -CommandName git -Native
        Get-Completer -CommandName git -ParameterName checkout, branch
        Unregister-Completer -CommandName C:\tools\example.exe -Native
        [pscustomobject] @{ CommandName = 'git'; ParameterName = 'checkout' } |
            Get-Completer

    A bare key input object fails with an error that names this topic:

        InputObject supplies the key 'git:checkout' without an IsNative or
        Native property. Keys are output-only identifiers and are no longer
        classified by their shape: add IsNative or Native alongside the key,
        or supply CommandName with Native or ParameterName. See
        about_CompleterActions_Migration.

    Records still round-trip. Every record Get-Completer, Register-Completer
    -PassThru, Import-CompleterScript, Import-CompleterSet, and
    Test-CompleterRegistration returns carries Key together with IsNative,
    so piping records back into Get-Completer, Register-Completer,
    Unregister-Completer, Test-CompleterRegistration, and Export-CompleterSet
    works as before:

        Get-Completer -CommandName git -Native | Unregister-Completer
        Import-CompleterScript -Path .\git_completer.ps1 | Get-Completer
        Test-CompleterRegistration -CommandName git -Native -InputText 'git ch' |
            Get-Completer

    An input object you build yourself may still carry a key, as long as it
    says which kind it is. Build it as a [pscustomobject]; a plain hashtable
    does not expose its entries as properties and is rejected:
    `[pscustomobject] @{ Key = 'git'; IsNative = $true }` resolves,
    `[pscustomobject] @{ Key = 'git' }` does not. Completer set files never
    used keys, so a set exported by 2.0.0-preview3 imports unchanged.

ONE STATE FILTER

    -ManagedOnly and -DiscoveredOnly were two switches that selected by
    origin. Get-Completer has one -State parameter of type CompleterState[]
    that selects by state; a scalar binds, several values return the union,
    and the values tab-complete: Active, Stale, Conflicted, Pending, Failed,
    Discovered. Without -State every record is returned.

    Before:

        Get-CompleterRegistration -ManagedOnly
        Get-CompleterRegistration -DiscoveredOnly
        Get-CompleterRegistration -ManagedOnly |
            Where-Object State -in Pending, Failed

    After:

        Get-Completer -State Active, Pending, Failed, Stale
        Get-Completer -State Discovered, Conflicted
        Get-Completer -State Pending, Failed

    The legacy Get-CompleterRegistration alias keeps -ManagedOnly and
    -DiscoveredOnly and translates them to exactly those state lists; it
    rejects either switch combined with -State. Get-Completer itself does not
    have the switches: `Get-Completer -ManagedOnly` fails with "A parameter
    cannot be found that matches parameter name 'ManagedOnly'".

    THE DISCOVERED STATE IS A BEHAVIOUR CHANGE. In 1.x a runtime registration
    that no managed record described reported State 'Active' with Source
    'Discovered'. In 2.0 the same record reports State 'Discovered'; 'Active'
    is reserved for managed records whose stored script is the live runtime
    value. Any check such as

        Get-CompleterRegistration | Where-Object State -eq Active

    that relied on runtime-only registrations being Active now returns the
    managed ones only. Use `-State Active, Discovered` for the old meaning.
    The Source property is unchanged ('Managed' or 'Discovered'), as are
    IsManaged and IsRuntimeRegistered, so a script that filtered on Source
    is unaffected.

    A second consequence of reporting every candidate's state once: a
    managed target that was replaced outside the module with
    Register-ArgumentCompleter now yields two records from an unfiltered
    Get-Completer, the managed record as 'Stale' and the live value as
    'Conflicted'. In 1.x only the Conflicted record was returned unless
    -ManagedOnly revealed the Stale one. The same applies to a Failed managed
    record whose target was re-registered externally (Failed plus
    Conflicted). Key is therefore unique in the output except for such
    replaced targets; select with -State when one of the two is wanted.

    The full state list:

    - Active a managed record whose stored script is the live runtime
                  value
    - Pending registered lazily and not loaded yet
    - Failed the lazy script failed to load; see LoadError
    - Stale a managed record whose runtime value was replaced or
                  removed outside this module
    - Conflicted a live runtime value that replaced a managed registration
                  outside this module
    - Discovered a live runtime value that no managed record describes

SORT ORDER

    Get-Completer sorts by CompleterType (native completers first), then
    CommandName, then ParameterName before -Skip and -First are applied.
    1.x returned records in the insertion order of its internal table, so a
    script that depended on that order sees a different order now. The
    upside is that paging across several calls stays stable while unrelated
    targets are registered or removed between pages; only a target that
    sorts before the current window can shift it. For a replaced target the
    Stale record sorts before its Conflicted twin.

TYPED OUTPUT

    The records are PowerShell classes defined by the module, each with the
    dotted PSTypeName it has always carried:

    - CompleterRegistration
      PSTypeName CompleterActions.CompleterRegistration
    - ImportedCompleterRegistration
      PSTypeName CompleterActions.ImportedCompleterRegistration
    - CompleterScriptFinding
      PSTypeName CompleterActions.CompleterScriptFinding
    - CompletionMatch
      PSTypeName CompleterActions.CompletionMatch

    Two enums back them: CompleterType (Native, Parameter) and
    CompleterState (Active, Stale, Conflicted, Pending, Failed, Discovered).
    Every command declares its record type in OutputType, so
    `(Get-Command Get-Completer).OutputType` is
    CompleterActions.CompleterRegistration.

    The dotted PSTypeName is still the contract. A PowerShell class cannot
    carry a dotted name, so each class has the bare name in the table and
    inserts the dotted name at the front of its PSTypeNames when it is
    constructed. Format views, `-is`-free duck typing, and
    `$record.PSTypeNames[0] -eq 'CompleterActions.CompleterRegistration'`
    checks all keep working. The classes are private to the module's session
    state, so `$record -is [CompleterRegistration]` and
    `[CompleterRegistration]::new()` only resolve inside the module; from a
    script, test the PSTypeName instead.

    Property names and order are unchanged, except that a completion match
    now carries IsNative after ParameterName so it round-trips like the
    other records. Four details differ from the 1.x pscustomobjects:

    - A piped record binds by value to the InputObject parameter, which is
      typed [object[]] on every command that takes records. Get-Completer
      no longer declares property-name binding on -CommandName,
      -ParameterName, and -Native, so an input object describes exactly one
      target: one whose CommandName or ParameterName holds several values
      is rejected with "InputObject supplies 2 values for CommandName";
      pass arrays to -CommandName and -ParameterName instead. Records the
      module returns always describe one target and are unaffected.
    - State and CompleterType are enum values, not strings. Comparisons with
      strings still work as before: `$_.State -eq 'Failed'`,
      `Where-Object State -in Pending, Failed`, and `-State Failed` all bind,
      and the value displays as its name. `$_.State.GetType()` is
      CompleterState rather than System.String.
    - String properties that had no value were $null on the 1.x records and
      are '' on the class records: ParameterName on a native record,
      ScriptPath and LoadError on a record without a script, and ToolTip on
      a completion match. `[string]::IsNullOrEmpty` and `-not $_.ScriptPath`
      behave the same; a `-eq $null` test does not match any more.
    - State and CompleterType serialize as their integer values through
      ConvertTo-Json and Export-Clixml, where the 1.x strings serialized as
      their names, so a record read back from either round trip carries 0
      instead of 'Active' and `$_.State -eq 'Active'` is false. Pass
      -EnumsAsStrings to ConvertTo-Json, or store `[string] $_.State` and
      `[string] $_.CompleterType`, when a script persists records.
      ConvertTo-Csv and the Format commands are unaffected because they
      write the name.

    Across a remoting or job boundary the records arrive deserialized, as
    they did in 1.x: the type name becomes
    Deserialized.CompleterActions.CompleterRegistration and State is a plain
    string such as 'Active', so `$_.State -eq 'Active'` still holds but
    `[CompleterState]` methods and the class itself are not available on
    the receiving side.

CHECKLIST FOR A PROFILE

    1. Replace the three old names with the new ones, or leave them and
       accept one warning per process per name until 3.0.
    2. Replace every -Key argument with -CommandName plus -Native or
       -ParameterName, and add IsNative to any hand-built input object that
       carries only a key.
    3. Replace -ManagedOnly with -State Active, Pending, Failed, Stale and
       -DiscoveredOnly with -State Discovered, Conflicted, or with the
       narrower state you meant.
    4. Review every `State -eq 'Active'` check: runtime-only registrations
       are Discovered now, and a replaced target returns both its Stale and
       its Conflicted record.
    5. Drop any reliance on insertion order; sort by whatever you need on
       top of the promised order.
    6. Replace `-eq $null` tests on ParameterName, ScriptPath, LoadError,
       or ToolTip with `[string]::IsNullOrEmpty` or a truthiness test.
    7. Where records are persisted with ConvertTo-Json or Export-Clixml, add
       -EnumsAsStrings or store `[string] $_.State` and
       `[string] $_.CompleterType`; the enums serialize as integers.
    8. Split any hand-built input object whose CommandName or ParameterName
       holds several values into one object per target, or pass the arrays
       to -CommandName and -ParameterName; Get-Completer rejects it now.

    Completer set files and completer scripts need no change.

EXAMPLE 1

    Move a profile from the eager 1.x pipeline to the 2.0 names:

        # 1.x
        Get-ChildItem ~\Completers -Filter *_completer.ps1 |
            Import-CompleterScript |
            Register-CompleterRegistration

        # 2.0
        Get-ChildItem ~\Completers -Filter *_completer.ps1 |
            Import-CompleterScript |
            Register-Completer

EXAMPLE 2

    Find the registrations that were made outside the module:

        # 1.x
        Get-CompleterRegistration -DiscoveredOnly |
            Where-Object State -eq Active

        # 2.0
        Get-Completer -State Discovered

EXAMPLE 3

    Remove a target by key:

        # 1.x
        Unregister-CompleterRegistration -Key 'git:checkout' -Confirm:$false

        # 2.0
        Unregister-Completer -CommandName git -ParameterName checkout `
            -Confirm:$false

SEE ALSO

    Get-Help Get-Completer -Full
    Get-Help Register-Completer -Full
    Get-Help Unregister-Completer -Full
    about_Import_Completers
    about_Completer_Sets