Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Escape deprecation messages before interpolating into source text #9371

Merged
merged 4 commits into from Apr 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG_PENDING.md
Expand Up @@ -14,3 +14,5 @@

### Bug Fixes

- [codegen/node] - Fix an issue with escaping deprecation messages.
[#9371](https://github.com/pulumi/pulumi/pull/9371)
8 changes: 4 additions & 4 deletions pkg/codegen/nodejs/gen.go
Expand Up @@ -648,7 +648,7 @@ func (mod *modContext) genResource(w io.Writer, r *schema.Resource) error {
fmt.Fprintf(w, " public static get(name: string, id: pulumi.Input<pulumi.ID>, %sopts?: pulumi.%s): %s {\n",
stateParam, optionsType, name)
if r.DeprecationMessage != "" && mod.compatibility != kubernetes20 {
fmt.Fprintf(w, " pulumi.log.warn(\"%s is deprecated: %s\")\n", name, r.DeprecationMessage)
fmt.Fprintf(w, " pulumi.log.warn(\"%s is deprecated: %s\")\n", name, escape(r.DeprecationMessage))
}
fmt.Fprintf(w, " return new %s(name, %s{ ...opts, id: id });\n", name, stateRef)
fmt.Fprintf(w, " }\n")
Expand Down Expand Up @@ -815,7 +815,7 @@ func (mod *modContext) genResource(w io.Writer, r *schema.Resource) error {
argsType, stateType, optionsType)
}
if r.DeprecationMessage != "" && mod.compatibility != kubernetes20 {
fmt.Fprintf(w, " pulumi.log.warn(\"%s is deprecated: %s\")\n", name, r.DeprecationMessage)
fmt.Fprintf(w, " pulumi.log.warn(\"%s is deprecated: %s\")\n", name, escape(r.DeprecationMessage))
}
fmt.Fprintf(w, " let resourceInputs: pulumi.Inputs = {};\n")
fmt.Fprintf(w, " opts = opts || {};\n")
Expand Down Expand Up @@ -954,7 +954,7 @@ func (mod *modContext) genResource(w io.Writer, r *schema.Resource) error {
fmt.Fprintf(w, " %s(%s): %s {\n", methodName, argsig, retty)
if fun.DeprecationMessage != "" {
fmt.Fprintf(w, " pulumi.log.warn(\"%s.%s is deprecated: %s\")\n", name, methodName,
fun.DeprecationMessage)
escape(fun.DeprecationMessage))
}

// Zero initialize the args if empty and necessary.
Expand Down Expand Up @@ -1084,7 +1084,7 @@ func (mod *modContext) genFunction(w io.Writer, fun *schema.Function) error {
fmt.Fprintf(w, "export function %s(%sopts?: pulumi.InvokeOptions): Promise<%s> {\n",
name, argsig, functionReturnType(fun))
if fun.DeprecationMessage != "" && mod.compatibility != kubernetes20 {
fmt.Fprintf(w, " pulumi.log.warn(\"%s is deprecated: %s\")\n", name, fun.DeprecationMessage)
fmt.Fprintf(w, " pulumi.log.warn(\"%s is deprecated: %s\")\n", name, escape(fun.DeprecationMessage))
}

// Zero initialize the args if empty and necessary.
Expand Down
15 changes: 15 additions & 0 deletions pkg/codegen/nodejs/utilities.go
Expand Up @@ -15,13 +15,15 @@
package nodejs

import (
"encoding/json"
"fmt"
"io"
"regexp"
"strings"
"unicode"

"github.com/pulumi/pulumi/pkg/v3/codegen"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
)

// isReservedWord returns true if s is a reserved word as per ECMA-262.
Expand Down Expand Up @@ -126,3 +128,16 @@ func makeSafeEnumName(name, typeName string) (string, error) {

return safeName, nil
}

// escape returns the string escaped for a JS string literal
func escape(s string) string {
// Seems the most fool-proof way of doing this is by using the JSON marshaler and then stripping the surrounding quotes
escaped, err := json.Marshal(s)
contract.AssertNoError(err)
contract.Assertf(len(escaped) >= 2, "JSON(%s) expected a quoted string but returned %s", s, escaped)
contract.Assertf(
escaped[0] == byte('"') && escaped[len(escaped)-1] == byte('"'),
"JSON(%s) expected a quoted string but returned %s", s, escaped)

return string(escaped)[1:(len(escaped) - 1)]
}
24 changes: 24 additions & 0 deletions pkg/codegen/nodejs/utilities_test.go
Expand Up @@ -43,3 +43,27 @@ func TestMakeSafeEnumName(t *testing.T) {
})
}
}

func TestEscape(t *testing.T) {
t.Parallel()
tests := []struct {
input string
expected string
}{
{"test", "test"},
{"sub\"string\"", "sub\\\"string\\\""},
{"slash\\s", "slash\\\\s"},
{"N\\A \"bad data\"", "N\\\\A \\\"bad data\\\""},
}
for _, tt := range tests {
tt := tt
t.Run(tt.input, func(t *testing.T) {
t.Parallel()

got := escape(tt.input)
if tt.expected != got {
t.Errorf("escape(%s) was %s want %s", tt.input, got, tt.expected)
}
})
}
}