Skip to content

Commit

Permalink
Don't use *schema.Package in nodejs codegen
Browse files Browse the repository at this point in the history
  • Loading branch information
iwahbe committed Dec 8, 2022
1 parent 65b6b01 commit b59bbcd
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 52 deletions.
4 changes: 2 additions & 2 deletions pkg/codegen/nodejs/doc.go
Expand Up @@ -77,7 +77,7 @@ func (d DocLanguageHelper) GetLanguageTypeString(pkg *schema.Package, moduleName
}

modCtx := &modContext{
pkg: pkg,
pkg: pkg.Reference(),
mod: moduleName,
}
typeName := modCtx.typeString(t, input, nil)
Expand Down Expand Up @@ -114,7 +114,7 @@ func (d DocLanguageHelper) GetMethodResultName(pkg *schema.Package, modName stri
if info, ok := pkg.Language["nodejs"].(NodePackageInfo); ok {
if info.LiftSingleValueMethodReturns && m.Function.Outputs != nil && len(m.Function.Outputs.Properties) == 1 {
modCtx := &modContext{
pkg: pkg,
pkg: pkg.Reference(),
mod: modName,
}
return modCtx.typeString(m.Function.Outputs.Properties[0].Type, false, nil)
Expand Down
103 changes: 63 additions & 40 deletions pkg/codegen/nodejs/gen.go
Expand Up @@ -128,7 +128,7 @@ func externalModuleName(s string) string {
}

type modContext struct {
pkg *schema.Package
pkg schema.PackageReference
mod string
types []*schema.ObjectType
enums []*schema.EnumType
Expand Down Expand Up @@ -180,15 +180,17 @@ func (mod *modContext) tokenToModName(tok string) string {
return modName
}

func (mod *modContext) namingContext(pkg *schema.Package) (namingCtx *modContext, pkgName string, external bool) {
func (mod *modContext) namingContext(pkg schema.PackageReference) (namingCtx *modContext, pkgName string, external bool) {
namingCtx = mod
if pkg != nil && pkg != mod.pkg {
if pkg != nil && !codegen.PkgEquals(pkg, mod.pkg) {
external = true
pkgName = pkg.Name + "."
pkgName = pkg.Name() + "."

var info NodePackageInfo
contract.AssertNoError(pkg.ImportLanguages(map[string]schema.Language{"nodejs": Importer}))
if v, ok := pkg.Language["nodejs"].(NodePackageInfo); ok {
def, err := pkg.Definition()
contract.AssertNoError(err)
contract.AssertNoError(def.ImportLanguages(map[string]schema.Language{"nodejs": Importer}))
if v, ok := def.Language["nodejs"].(NodePackageInfo); ok {
info = v
}
namingCtx = &modContext{
Expand All @@ -200,7 +202,7 @@ func (mod *modContext) namingContext(pkg *schema.Package) (namingCtx *modContext
return
}

func (mod *modContext) objectType(pkg *schema.Package, details *typeDetails, tok string, input, args, enum bool) string {
func (mod *modContext) objectType(pkg schema.PackageReference, details *typeDetails, tok string, input, args, enum bool) string {

root := "outputs."
if input {
Expand Down Expand Up @@ -238,7 +240,7 @@ func (mod *modContext) objectType(pkg *schema.Package, details *typeDetails, tok
func (mod *modContext) resourceType(r *schema.ResourceType) string {
if strings.HasPrefix(r.Token, "pulumi:providers:") {
pkgName := strings.TrimPrefix(r.Token, "pulumi:providers:")
if pkgName != mod.pkg.Name {
if pkgName != mod.pkg.Name() {
pkgName = externalModuleName(pkgName)
}

Expand All @@ -247,7 +249,7 @@ func (mod *modContext) resourceType(r *schema.ResourceType) string {

pkg := mod.pkg
if r.Resource != nil {
pkg = r.Resource.Package
pkg = r.Resource.PackageReference
}
namingCtx, pkgName, external := mod.namingContext(pkg)
if external {
Expand Down Expand Up @@ -298,14 +300,14 @@ func (mod *modContext) typeAst(t schema.Type, input bool, constValue interface{}
}
return tstypes.Identifier(fmt.Sprintf("pulumi.Input<%s>", typ))
case *schema.EnumType:
return tstypes.Identifier(mod.objectType(t.Package, nil, t.Token, input, false, true))
return tstypes.Identifier(mod.objectType(t.PackageReference, nil, t.Token, input, false, true))
case *schema.ArrayType:
return tstypes.Array(mod.typeAst(t.ElementType, input, constValue))
case *schema.MapType:
return tstypes.StringMap(mod.typeAst(t.ElementType, input, constValue))
case *schema.ObjectType:
details := mod.details(t)
return tstypes.Identifier(mod.objectType(t.Package, details, t.Token, input, t.IsInputShape(), false))
return tstypes.Identifier(mod.objectType(t.PackageReference, details, t.Token, input, t.IsInputShape(), false))
case *schema.ResourceType:
return tstypes.Identifier(mod.resourceType(t))
case *schema.TokenType:
Expand Down Expand Up @@ -670,7 +672,7 @@ func (mod *modContext) genResource(w io.Writer, r *schema.Resource) (resourceFil

pulumiType := r.Token
if r.IsProvider {
pulumiType = mod.pkg.Name
pulumiType = mod.pkg.Name()
}

fmt.Fprintf(w, " /** @internal */\n")
Expand Down Expand Up @@ -1314,7 +1316,9 @@ func (mod *modContext) getTypeImportsForResource(t schema.Type, recurse bool, ex
}

var nodePackageInfo NodePackageInfo
if languageInfo, hasLanguageInfo := mod.pkg.Language["nodejs"]; hasLanguageInfo {
def, err := mod.pkg.Definition()
contract.AssertNoError(err)
if languageInfo, hasLanguageInfo := def.Language["nodejs"]; hasLanguageInfo {
nodePackageInfo = languageInfo.(NodePackageInfo)
}

Expand All @@ -1337,16 +1341,16 @@ func (mod *modContext) getTypeImportsForResource(t schema.Type, recurse bool, ex
return mod.getTypeImports(t.ElementType, recurse, externalImports, imports, seen)
case *schema.EnumType:
// If the enum is from another package, add an import for the external package.
if t.Package != nil && t.Package != mod.pkg {
pkg := t.Package.Name
if t.PackageReference != nil && !codegen.PkgEquals(t.PackageReference, mod.pkg) {
pkg := t.PackageReference.Name()
writeImports(pkg)
return false
}
return true
case *schema.ObjectType:
// If it's from another package, add an import for the external package.
if t.Package != nil && t.Package != mod.pkg {
pkg := t.Package.Name
if t.PackageReference != nil && !codegen.PkgEquals(t.PackageReference, mod.pkg) {
pkg := t.PackageReference.Name()
writeImports(pkg)
return false
}
Expand All @@ -1357,8 +1361,8 @@ func (mod *modContext) getTypeImportsForResource(t schema.Type, recurse bool, ex
return true
case *schema.ResourceType:
// If it's from another package, add an import for the external package.
if t.Resource != nil && t.Resource.Package != mod.pkg {
pkg := t.Resource.Package.Name
if t.Resource != nil && !codegen.PkgEquals(t.Resource.PackageReference, mod.pkg) {
pkg := t.Resource.PackageReference.Name()
writeImports(pkg)
return false
}
Expand Down Expand Up @@ -1510,7 +1514,7 @@ func (mod *modContext) genConfig(w io.Writer, variables []*schema.Property) erro
fmt.Fprintf(w, "declare var exports: any;\n")

// Create a config bag for the variables to pull from.
fmt.Fprintf(w, "const __config = new pulumi.Config(\"%v\");\n", mod.pkg.Name)
fmt.Fprintf(w, "const __config = new pulumi.Config(\"%v\");\n", mod.pkg.Name())
fmt.Fprintf(w, "\n")

// Emit an entry for all config variables.
Expand Down Expand Up @@ -1561,9 +1565,11 @@ func (mod *modContext) sdkImports(nested, utilities bool) []string {
fmt.Sprintf(`import * as outputs from "%s/types/output";`, relRoot),
}...)

if mod.pkg.Language["nodejs"].(NodePackageInfo).ContainsEnums {
def, err := mod.pkg.Definition()
contract.AssertNoError(err)
if def.Language["nodejs"].(NodePackageInfo).ContainsEnums {
code := `import * as enums from "%s/types/enums";`
if lookupNodePackageInfo(mod.pkg).UseTypeOnlyReferences {
if lookupNodePackageInfo(def).UseTypeOnlyReferences {
code = `import type * as enums from "%s/types/enums";`
}
imports = append(imports, fmt.Sprintf(code, relRoot))
Expand Down Expand Up @@ -1754,7 +1760,9 @@ func (mod *modContext) isReservedSourceFileName(name string) bool {
case "utilities.ts":
return mod.mod == ""
case "vars.ts":
return len(mod.pkg.Config) > 0
config, err := mod.pkg.Config()
contract.AssertNoError(err)
return len(config) > 0
default:
return false
}
Expand Down Expand Up @@ -1800,36 +1808,44 @@ func (mod *modContext) gen(fs codegen.Fs) error {
fs.Add(p, []byte(contents))
}

def, err := mod.pkg.Definition()
if err != nil {
return err
}

// Utilities, config, readme
switch mod.mod {
case "":
buffer := &bytes.Buffer{}
mod.genHeader(buffer, nil, nil, nil)
mod.genUtilitiesFile(buffer)
err := mod.genUtilitiesFile(buffer)
if err != nil {
return err
}
fs.Add(path.Join(modDir, "utilities.ts"), buffer.Bytes())

// Ensure that the top-level (provider) module directory contains a README.md file.
readme := mod.pkg.Language["nodejs"].(NodePackageInfo).Readme
readme := def.Language["nodejs"].(NodePackageInfo).Readme
if readme == "" {
readme = mod.pkg.Description
readme = def.Description
if readme != "" && readme[len(readme)-1] != '\n' {
readme += "\n"
}
if mod.pkg.Attribution != "" {
if def.Attribution != "" {
if len(readme) != 0 {
readme += "\n"
}
readme += mod.pkg.Attribution
readme += def.Attribution
}
}
if readme != "" && readme[len(readme)-1] != '\n' {
readme += "\n"
}
fs.Add(path.Join(modDir, "README.md"), []byte(readme))
case "config":
if len(mod.pkg.Config) > 0 {
if len(def.Config) > 0 {
buffer := &bytes.Buffer{}
if err := mod.genConfig(buffer, mod.pkg.Config); err != nil {
if err := mod.genConfig(buffer, def.Config); err != nil {
return err
}
addFile(otherFileType, "vars.ts", buffer.String())
Expand Down Expand Up @@ -1904,7 +1920,7 @@ func (mod *modContext) gen(fs codegen.Fs) error {

// Nested types
// Importing enums always imports inputs and outputs, so if we have enums we generate inputs and outputs
if len(mod.types) > 0 || (mod.pkg.Language["nodejs"].(NodePackageInfo).ContainsEnums && mod.mod == "types") {
if len(mod.types) > 0 || (def.Language["nodejs"].(NodePackageInfo).ContainsEnums && mod.mod == "types") {
input, output, err := mod.genTypes()
if err != nil {
return err
Expand Down Expand Up @@ -1975,7 +1991,10 @@ func (mod *modContext) genIndex(exports []fileInfo) string {
}
}

info, _ := mod.pkg.Language["nodejs"].(NodePackageInfo)
def, err := mod.pkg.Definition()
contract.AssertNoError(err)

info, _ := def.Language["nodejs"].(NodePackageInfo)
if info.ContainsEnums {
if mod.mod == "types" {
children.Add("enums")
Expand Down Expand Up @@ -2050,7 +2069,7 @@ func (mod *modContext) genResourceModule(w io.Writer) {
continue
}

registrations.Add(mod.pkg.TokenToRuntimeModule(r.Token))
registrations.Add(schema.TokenToRuntimeModule(r.Token))
}

fmt.Fprintf(w, "\nconst _module = {\n")
Expand Down Expand Up @@ -2078,12 +2097,12 @@ func (mod *modContext) genResourceModule(w io.Writer) {
fmt.Fprintf(w, " },\n")
fmt.Fprintf(w, "};\n")
for _, name := range registrations.SortedValues() {
fmt.Fprintf(w, "pulumi.runtime.registerResourceModule(\"%v\", \"%v\", _module)\n", mod.pkg.Name, name)
fmt.Fprintf(w, "pulumi.runtime.registerResourceModule(\"%v\", \"%v\", _module)\n", mod.pkg.Name(), name)
}
}

if provider != nil {
fmt.Fprintf(w, "pulumi.runtime.registerResourcePackage(\"%v\", {\n", mod.pkg.Name)
fmt.Fprintf(w, "pulumi.runtime.registerResourcePackage(\"%v\", {\n", mod.pkg.Name())
fmt.Fprintf(w, " version: utilities.getVersion(),\n")
fmt.Fprintf(w, " constructProvider: (name: string, type: string, urn: string): pulumi.ProviderResource => {\n")
fmt.Fprintf(w, " if (type !== \"%v\") {\n", provider.Token)
Expand Down Expand Up @@ -2352,7 +2371,7 @@ func generateModuleContextMap(tool string, pkg *schema.Package, extraFiles map[s
mod, ok := modules[modName]
if !ok {
mod = &modContext{
pkg: pkg,
pkg: pkg.Reference(),
mod: modName,
tool: tool,
compatibility: info.Compatibility,
Expand Down Expand Up @@ -2571,7 +2590,7 @@ func GeneratePackage(tool string, pkg *schema.Package, extraFiles map[string][]b
return files, nil
}

func (mod *modContext) genUtilitiesFile(w io.Writer) {
func (mod *modContext) genUtilitiesFile(w io.Writer) error {
const body = `
export function getEnv(...vars: string[]): string | undefined {
for (const v of vars) {
Expand Down Expand Up @@ -2636,12 +2655,16 @@ export function lazyLoad(exports: any, props: string[], loadModule: any) {
}
}
`
def, err := mod.pkg.Definition()
if err != nil {
return err
}
var pluginDownloadURL string
if url := mod.pkg.PluginDownloadURL; url != "" {
if url := def.PluginDownloadURL; url != "" {
pluginDownloadURL = fmt.Sprintf(", pluginDownloadURL: %q", url)
}
_, err := fmt.Fprintf(w, body, pluginDownloadURL)
contract.AssertNoError(err)
_, err = fmt.Fprintf(w, body, pluginDownloadURL)
return err
}

func genInstallScript(pluginDownloadURL string) string {
Expand Down
26 changes: 18 additions & 8 deletions pkg/codegen/nodejs/gen_program.go
Expand Up @@ -73,7 +73,10 @@ func GenerateProgram(program *pcl.Program) (map[string][]byte, hcl.Diagnostics,
}

var index bytes.Buffer
g.genPreamble(&index, program, preambleHelperMethods)
err = g.genPreamble(&index, program, preambleHelperMethods)
if err != nil {
return nil, nil, err
}
for _, n := range nodes {
if g.asyncMain {
break
Expand Down Expand Up @@ -281,7 +284,7 @@ func (g *generator) genComment(w io.Writer, comment syntax.Comment) {
}
}

func (g *generator) genPreamble(w io.Writer, program *pcl.Program, preambleHelperMethods codegen.StringSet) {
func (g *generator) genPreamble(w io.Writer, program *pcl.Program, preambleHelperMethods codegen.StringSet) error {
// Print the @pulumi/pulumi import at the top.
g.Fprintln(w, `import * as pulumi from "@pulumi/pulumi";`)

Expand All @@ -296,8 +299,12 @@ func (g *generator) genPreamble(w io.Writer, program *pcl.Program, preambleHelpe
continue
}
pkgName := "@pulumi/" + pkg
if r.Schema != nil && r.Schema.Package != nil {
if info, ok := r.Schema.Package.Language["nodejs"].(NodePackageInfo); ok && info.PackageName != "" {
if r.Schema != nil && r.Schema.PackageReference != nil {
def, err := r.Schema.PackageReference.Definition()
if err != nil {
return err
}
if info, ok := def.Language["nodejs"].(NodePackageInfo); ok && info.PackageName != "" {
pkgName = info.PackageName
}
npmToPuPkgName[pkgName] = pkg
Expand Down Expand Up @@ -345,6 +352,7 @@ func (g *generator) genPreamble(w io.Writer, program *pcl.Program, preambleHelpe
for _, preambleHelperMethodBody := range preambleHelperMethods.SortedValues() {
g.Fprintf(w, "%s\n\n", preambleHelperMethodBody)
}
return nil
}

func (g *generator) genNode(w io.Writer, n pcl.Node) {
Expand Down Expand Up @@ -384,18 +392,20 @@ func resourceTypeName(r *pcl.Resource) (string, string, string, hcl.Diagnostics)
pkg, module, member, diagnostics := r.DecomposeToken()

if r.Schema != nil {
module = moduleName(module, r.Schema.Package)
module = moduleName(module, r.Schema.PackageReference)
}

return makeValidIdentifier(pkg), module, title(member), diagnostics
}

func moduleName(module string, pkg *schema.Package) string {
func moduleName(module string, pkg schema.PackageReference) string {
// Normalize module.
if pkg != nil {
err := pkg.ImportLanguages(map[string]schema.Language{"nodejs": Importer})
def, err := pkg.Definition()
contract.AssertNoError(err)
err = def.ImportLanguages(map[string]schema.Language{"nodejs": Importer})
contract.AssertNoError(err)
if lang, ok := pkg.Language["nodejs"]; ok {
if lang, ok := def.Language["nodejs"]; ok {
pkgInfo := lang.(NodePackageInfo)
if m, ok := pkgInfo.ModuleToPackage[module]; ok {
module = m
Expand Down

0 comments on commit b59bbcd

Please sign in to comment.