Skip to content

Commit

Permalink
Escape deprecation messages before interpolating into source text (#9371
Browse files Browse the repository at this point in the history
)

* Escape deprecation messages before interpolating into source text

Fixes #9342

* Add to CHANGELOG

* Move to utilities.go

* lint
  • Loading branch information
Frassle committed Apr 8, 2022
1 parent 427d863 commit 7a25733
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 4 deletions.
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)
}
})
}
}

0 comments on commit 7a25733

Please sign in to comment.