When completing an empty value position (e.g., `runs-on: |`), add special
completions that let users switch to alternative structural forms:
- "(switch to list)" - restructures to `key:\n - `
- "(switch to mapping)" - restructures to `key:\n `
These help users escape "dead end" situations where the current form has
no valid completions but alternative forms are available in the schema.
- Move qualifiers (list, full syntax) from label to detail field
- Remove filterText since labels are now clean
- Update distinctValues to preserve variants with different details
- Standard LSP pattern: detail shown after label in completion UI
Recent autocomplete improvements (typing activation, completion chaining, schema
variant surfacing) now guide users to discover the full schema naturally. This
change removes the legacy behavior that showed invalid options and silently
transformed YAML upon insertion.
Key changes:
- Filter one-of completion options based on the token's actual structural type
- When user commits to scalar (non-empty string), only show scalar options
- When user commits to mapping/sequence, only show those options
- Skip null-only scalars in Key mode to prevent clobbering string constants
- Scalar event completions (e.g., check_run at 'on: |') now insert inline
This ensures that when a user explicitly chooses a simplified form, they only
see values valid for that form, creating a cleaner and more predictable
autocomplete experience.
* Expand one-of keys to multiple completion items
Some workflow fields accept multiple YAML structures (scalar, sequence, or
mapping), but completions previously only showed a single option—leaving users
unaware of the full schema flexibility. This change surfaces structural options
and inserts the correct YAML scaffolding so users land in the right place to
keep typing.
Example: runs-on
Completing runs-on now shows three options:
- runs-on → Ready for a string like ubuntu-latest
- runs-on (list) → Ready to add runner labels
- runs-on (full syntax) → Ready for labels:, group:, etc.
Notes:
- Qualifiers (list) and (full syntax) only appear when multiple structural types exist
- Scalar completions use the plain key name
- Qualified variants use filterText matching the base key
* Sort expanded one-of completions: scalar, list, full syntax
Migrate expressions, workflow-parser, and languageservice packages to use
proper ESM imports with .js extensions that work with node16 moduleResolution.
Changes:
- Update tsconfig.build.json in each package to use module: node16 and
moduleResolution: node16
- Add .js extensions to all relative import paths (Option B approach)
- Fix yaml internal type imports in workflow-parser by defining local types
- Add skipLibCheck to handle @types/node compatibility issues
- Add TypeScript 5.8.3 override in root package.json
- Add ESM migration plan documentation
The languageserver package is deferred due to test hang issues that need
further investigation.
Related #154 - Upgrade moduleResolution from node to node16 or nodenext
Related #110 - Published ESM code has imports without file extensions
Related #64 - expressions: ERR_MODULE_NOT_FOUND attempting to run example
Related #146 - Can not import @actions/workflow-parser
Test results:
- expressions: 1068 tests passed
- workflow-parser: 292 tests passed
- languageservice: 452 tests passed
* docs: update ESM migration plan with findings
- Update languageserver blocker: vscode-languageserver v8.0.2 lacks ESM
exports (not a test hang issue)
- Document that Option B (manual .js extensions) was chosen over Option A
due to ts-jest compatibility issues
- Add workaround for yaml package internal types (LinePos, NodeBase)
- Update migration status table with accurate reason for deferral
- Add skipLibCheck note for @types/node compatibility
Fixed the cursor offset calculation for multi-line strings. The original
code unconditionally added +1 for a newline separator, but when the cursor
is on the first content line, there are no lines before it, so adding +1
produced an off-by-one error.
Fixes: vscode-github-actions#81