export async function addMissingParameters()

in src/documents/parameters/ParameterValues.ts [116:200]


export async function addMissingParameters(
    parameterDefinitionsSource: IParameterDefinitionsSource,
    parameterValuesSource: IParameterValuesSource,
    // An editor for the the parameter values source document
    parameterValuesSourceEditor: TextEditor,
    parentParameterDefinitions: IParameterDefinitionsSource | undefined,
    onlyRequiredParameters: boolean
): Promise<void> {
    // We don't currently handle the case where there is no "parameters" object

    // Find the location to insert new stuff in the parameters section
    const parameterValuesDocument = parameterValuesSource.document;
    const parametersObjectValue = parameterValuesSource.parameterValuesProperty?.value?.asObjectValue;
    if (parameterValuesSource.parameterValuesProperty && parametersObjectValue) {
        // Where insert?
        // Find last non-whitespace token inside the parameters section
        const parametersProperty = parameterValuesSource.parameterValuesProperty;
        let lastTokenInParameters: Json.Token | undefined;
        for (let i = parametersProperty.span.endIndex - 1; // Start before the closing "}"
            i >= parametersProperty.span.startIndex;
            --i) {
            lastTokenInParameters = parameterValuesDocument.jsonParseResult.getTokenAtCharacterIndex(i, Json.Comments.includeCommentTokens);
            if (lastTokenInParameters) {
                break;
            }
        }
        const insertIndex: number = lastTokenInParameters
            ? lastTokenInParameters.span.afterEndIndex
            : parametersObjectValue.span.endIndex;
        const insertPosition = parameterValuesDocument.getDocumentPosition(insertIndex);

        const missingParams: IParameterDefinition[] = getMissingParameters(
            parameterDefinitionsSource,
            parameterValuesSource,
            onlyRequiredParameters);

        if (missingParams.length === 0) {
            return;
        }

        // Create insertion text
        let paramsAsText: string[] = [];
        for (let param of missingParams) {
            const paramText = createParameterFromTemplateParameter(parameterDefinitionsSource, param, parentParameterDefinitions, defaultTabSize);
            paramsAsText.push(paramText);
        }
        let newText = paramsAsText.join(`,${EOL}`);

        // Determine indentation
        const parametersObjectIndent = parameterValuesDocument.getDocumentPosition(parametersProperty?.nameValue.span.startIndex).column;
        const lastParameter = parameterValuesSource.parameterValueDefinitions.length > 0 ? parameterValuesSource.parameterValueDefinitions[parameterValuesSource.parameterValueDefinitions.length - 1] : undefined;
        const lastParameterIndent = lastParameter ? parameterValuesDocument.getDocumentPosition(lastParameter?.fullSpan.startIndex).column : undefined;
        const newTextIndent = lastParameterIndent === undefined ? parametersObjectIndent + defaultTabSize : lastParameterIndent;
        let indentedText = indentMultilineString(newText, newTextIndent);
        let insertText = EOL + indentedText;

        // If insertion point is on the same line as the end of the parameters object, then add a newline
        // afterwards and indent it (e.g. parameters object = empty, {})
        if (parameterValuesDocument.getDocumentPosition(insertIndex).line
            === parameterValuesDocument.getDocumentPosition(parametersObjectValue.span.endIndex).line
        ) {
            insertText += EOL + ' '.repeat(defaultTabSize);
        }

        // Add comma before?
        let commaEdit = createEditToAddCommaBeforePosition(parameterValuesSource, insertIndex);
        assert(!commaEdit || commaEdit.span.endIndex <= insertIndex);
        if (commaEdit?.span.startIndex === insertIndex) {
            // vscode doesn't like both edits starting at the same location, so
            //   just add the comma directly to the string (this is the common case)
            commaEdit = undefined;
            insertText = `,${insertText}`;
        }

        await parameterValuesSourceEditor.edit(editBuilder => {

            editBuilder.insert(getVSCodePositionFromPosition(insertPosition), insertText);
            if (commaEdit) {
                editBuilder.replace(
                    getVSCodeRangeFromSpan(parameterValuesDocument, commaEdit.span),
                    commaEdit.insertText);
            }
        });
    }
}