Skip to content

Add a New Resource

Resources are locale-specific data files (names, cities, words) that Pseudata uses to generate realistic, culturally appropriate test data. This guide shows you how to add new resources and make them available across all SDKs.

Resources follow a different path than models:

Code Generation Flow

resource-emitter.js reads your text files from typespec/resources/ and embeds them directly into the generated SDK code, making them available at runtime without file I/O.

Resources are organized into atomic modules by scope:

  1. Global: typespec/resources/general/email_domains.txt
  2. Language-level: typespec/resources/lang/en/adjectives.txt
  3. Country-level: typespec/resources/country/us/timezones.txt
  4. Locale-specific: typespec/resources/locale/en_us/cities.txt

Note: All directory and file names use lowercase (e.g., en_us, email_domains.txt) for cross-platform consistency.

Choose the appropriate level for your resource:

Locale-specific (en_us, fr_fr, ja_jp)

  • typespec/resources/locale/en_us/
  • Given names and family names
  • City names
  • Street names
  • Data that varies by both language and country

Language-level (en, fr, ja)

  • typespec/resources/lang/en/
  • Common nouns, adjectives, verbs
  • Month and weekday names
  • Generic words for that language
  • Data that’s language-dependent but not country-specific

Country-level (us, gb, jp)

  • typespec/resources/country/us/
  • Phone number formats
  • Postal code patterns
  • Address formats
  • Timezones
  • Data that’s country-dependent but not language-specific

Global

  • typespec/resources/general/
  • Email domains
  • File extensions
  • Data that’s universal across all locales

Create a text file with one entry per line. Let’s add job titles as an example.

For locale-specific resources (US English):

Terminal window
# Create en_us directory if it doesn't exist
mkdir -p typespec/resources/locale/en_us
# Add job titles specific to US market
cat > typespec/resources/locale/en_us/job_titles.txt << EOF
Software Engineer
Product Manager
Data Scientist
UX Designer
DevOps Engineer
Sales Executive
Marketing Director
EOF

For language-level resources (English in general):

Terminal window
# Create en directory if it doesn't exist
mkdir -p typespec/resources/lang/en
# Add generic English job titles
cat > typespec/resources/lang/en/job_titles.txt << EOF
Manager
Engineer
Designer
Analyst
Consultant
Director
Coordinator
EOF

Add a field to the Resources model in typespec/src/pseudata.tsp:

model Resources {
// ... existing fields like givenMaleNames, cities, etc. ...
/**
* List of job titles.
* Used for generating professional titles.
*/
jobTitles: string[];
}

Modify typespec/lib/resource-emitter.js to load your new resource.

Find the loadResourcesForLocale() function and add your resource to the returned object:

return {
// ... existing resources ...
givenMaleNames: loadResourceFile(locale, country, language, "given_male_names.txt") || [],
givenFemaleNames: loadResourceFile(locale, country, language, "given_female_names.txt") || [],
// Add your new resource
jobTitles: loadResourceFile(locale, country, language, "job_titles.txt") || [],
};

If you want a dedicated primitive method for easy access:

Add the signature to typespec/src/primitives.tsp:

interface Primitives {
// ... existing primitives ...
/**
* Generates a job title.
* Selected from locale-specific job titles pool.
*/
jobTitle(): string;
}

Then implement in all supported languages:

// Go - primitives_impl.go
func (p *PrimitivesImpl) JobTitle() string {
data := p.resources()
titles := data.JobTitles
return p.Element(titles)
}
// Java - PrimitivesImpl.java
@Override
public String jobTitle() {
Resources data = resources();
String[] titles = data.jobTitles;
return element(titles);
}
# Python - primitives_impl.py
def job_title(self) -> str:
"""Generates a job title."""
data = self._resources()
titles = data["jobTitles"]
return self.element(titles)
// TypeScript - primitives-impl.ts
jobTitle(): string {
const data = this.resources();
const titles = data.jobTitles;
return this.element(titles);
}

Generate the updated SDK code:

Terminal window
cd pseudata-poc
task generate

Atomic Modules (for tree-shaking):

  • resources/general/data.{go,java,py,ts}: Global resources module
  • resources/lang/en/data.{go,java,py,ts}: English language resources module
  • resources/country/us/data.{go,java,py,ts}: US country resources module
  • resources/locale/en_us/data.{go,java,py,ts}: US English locale resources module

Regional Bundles:

  • resources/bundles/us.{go,java,py,ts}: Composes atomic modules for US
  • resources/bundles/world.{go,java,py,ts}: Composes all atomic modules
  • 25 other geographic and business bundles

Monolithic Export (for convenience):

  • resources.{go,java,py,ts}: All locales in one file (backward compatibility)

Resource data is embedded directly in code for all locales, with no runtime file I/O needed.

Access resources directly from code:

// Go - Direct access
data := p.resources()
titles := data.JobTitles
title := titles[index % len(titles)]

Or use via primitive in models:

model Employee {
@generator("id")
id: string;
@generator("jobTitle")
job: string;
}

Or in templates:

model Employee {
@generator("id")
id: string;
@template("{jobTitle} at {companyName}")
title: string;
}

If you created a new primitive that uses your resource, add fixture tests to ensure cross-language consistency. See the Testing Guide for details on how fixture-based testing works.

Resources have language-specific access patterns that must be tested:

  • Loading: Resource file must exist and be embedded correctly
  • Access: Dictionary vs. property syntax varies by language
  • Determinism: Same seed must select same item from resource array

Test the primitive that uses your resource:

{
"testCases": [
{
"name": "jobTitle_en_US",
"worldSeed": 42,
"typeSeq": 0,
"index": 0,
"locale": "en_US",
"expected": "Software Engineer"
},
{
"name": "jobTitle_different_seed",
"worldSeed": 100,
"typeSeq": 0,
"index": 0,
"locale": "en_US",
"expected": "Product Manager"
}
]
}
  1. Add test in Go (primitives_test.go):
func TestJobTitleFixtures(t *testing.T) {
fixture := loadFixture("fixtures/primitives_test_vectors.json")
for _, tc := range fixture.TestCases {
p := NewPrimitivesImpl(tc.WorldSeed, tc.TypeSeq, tc.Index)
// Set locale if needed
got := p.JobTitle()
assert.Equal(t, tc.Expected, got, tc.Name)
}
}
  1. Run go test -update to generate/update fixtures

  2. Implement equivalent tests in other languages

This catches resource loading bugs, access pattern errors, and ensures deterministic selection across all SDKs.

File Format

  • One entry per line
  • UTF-8 encoding
  • No empty lines (they’ll be included as empty strings)
  • Trim whitespace from entries

Naming Conventions

  • Use snake_case for file names: job_titles.txt, street_suffixes.txt
  • Match the TypeSpec field name: jobTitlesjob_titles.txt

Resource Size

  • Keep files under 10MB for faster compilation
  • For large datasets, consider splitting into multiple resources
  • Resources are embedded in code, so size affects binary size

Locale Coverage

  • Start with en_US as the reference implementation
  • Add other locales incrementally based on need
  • Each locale must have its own complete resource files