Homework 2: Type Validation

Due September 17th at 11:59 PM

Topics: TypeScript, Zod Validation, Unit Testing, Project Management

In this homework, you will be building a TypeScript project from scratch: we will provide you no starter code, not even a package.json or configuration files like before! You will only be given some JSON files including data that you must validate using TypeScript and the Zod package. With the knowledge from the lecture on project mananagement, you'll get to step into the shoes of a developer to choose all the tools you need for a project yourself- with some guidance, of course.

This homework is an exercise in exploring documentation, especially with working on TypeScript and Zod. In your time as a JavaScript developer, you'll come across many interesting modules that you may want to incorporate into your projects. It is paramount to get familiar with the process of installing, using, and updating these modules within projects.

Assignment Goals

  • Use TypeScript in a project alongside the Zod package for validation
  • Develop project management skills in JavaScript by building a project and its dependencies from scratch
  • Learn the ecosystem of npm modules

Introduction and Installation

Starter Code

In this assignment, you will be validating inventory data for an fictional online store that sells JavaScript merchandise called BazaarJS. The only items in your starter code are multiple store inventory catalogs in the form of JSON Files. Imagine you were given these JSON files by a co-worker to validate, or you queried this data from an API or a database. Your task is to build a TypeScript project that can perform this validation.

You will need to following dependencies to develop this application:

  • typescript
  • @types/node
  • zod
  • eslint & typescript-eslint
  • prettier
  • jest & ts-jest

This may not be an exhaustive list of the dependencies you need for this project. You are free to install any other packages that may help for this project, so long as the core of the project still uses TypeScript and Zod.

Your project must have a script called build that invokes tsc to compile your TypeScript files into an output directory. You may use any TypeScript configuration that works for you so long as the build command works to compile your code. While there's no strict file naming conventions for this project, we recommend you use some default names, such as src for your source code/input directory and dist for your output directory where your .ts files will compile into .js files.

Instructions

Part 1: Installation and Setup

You should first setup your project and install your dependencies. Make sure to keep your project root in one folder so that you can easily submit all the files in your project at the end.

Fill out your package.json with proper metadata, including the project name, description, author, the name of the main script (the entry point for this application), and a license name. For the license,

  • Choose some open-source license (we recommend ISC)
  • Create a LICENSE.txt file next to your package.json
  • Add the placeholder text from the license, then fill in placeholders like year and owner

At this point, your project is setup, and ready to publish to npm if you so choose! (through we won't require you to publish it for this homework)

Part 2: Schema

Your first task is to create a Zod schema for the data within the provided JSON file. This data consists of products within the online store that may have some common properties, and some differing properties based on their category. Start by taking a look at the JSON file to familiarize yourself with the shape of the data you will be validating.

Each product must contain the following common properties:

  • id — a positive integer
  • name — a non-empty string
  • price — a number greater than 0
  • category — a string, among the literals "apparel", "accessories", or "stickers"
  • inStock — a boolean
  • tags — an array containing at least one string
  • seller — an object containing a valid seller schema (see below)

A seller must contain the following properties:

  • id — a positive integer
  • name — a non-empty string
  • rating — a number between 0 and 5

The category property determines which additional properties are required for a product. Your schema must represent these different product types as a discriminated union using category as the discriminator.

Apparel

An apparel product must have acategory of "apparel"and must also contain:

  • size — one of S, M, L, or XL
  • material — a non-empty string

Accessories

An accessories product must have acategory of "accessories"and must also contain:

  • color — a non-empty string
  • compatibleWith — an array containing at least one string

Stickers

A stickers product must have acategory of "stickers"and must also contain:

  • stickerCount — a positive integer
  • waterproof — a boolean

Finally, create an array schema that represents the entire contents of the JSON file. The root value of the file should be an array containing only valid products. This schema should represent your discriminated union of the three types of products.

Hints and Zod Syntax

We recommend you create smaller schemas first and combine them to create your final product schema.

There are likely many ways to use Zod to arrive at the schema defined above. You are free to explore Zod's different methods to create your final product schema. Zod's z.object(), z.literal(), z.enum(), z.discriminatedUnion(), z.array(), and z.infer() may be useful.

Important: Do not make all category-specific properties optional. The category should determine which properties are required for each product.

Part 3: Parsing and Validation

Write a function that takes in a file name (the JSON data) and outputs various console logs based on the contents of the file alongside a validation result object. Within this function, parse the input JSON using fs.readFileSync() (similar to HW1). Then, use Zod to validate that JSON data against your defined product array schema (not the inferred TypeScript type) with safeParse().

Validation will either succeed or fail.

If validation succeeds:

  • Print out a success message.
  • Print out the total number of products.
  • List each product id, name, category, and at least one of the additional properties of the category in a single formatted string.
  • Return the result object

If validation fails:

  • Print out a failure message.
  • List out the products that had validation errors, and their associated error message.
  • Return the result object

Testing, before Unit Testing

You'll be writing unit tests in the section right after this. However, you may it helpful to test your TypeScript code right now. You can run the build command and compile your TS code into JS, and run the file manually (with the command node [filename]). There are modules out there that allow you to run directly from .ts files, if you so choose.

Remember that if you do choose to build, any updates to the .ts won't be reflected in the .js compiled file until you run the build command again!

Part 4: Unit Testing

In preparation to test, export the validation function you just wrote so that your test files can use it as a module.

You will set up and write some unit tests for your project. We will be using Jest for this purpose, so look up how to install and use the syntax of Jest in order to prepare your test suite. We'd recommend using ts-jest alongside this, but feel free to find your own solution if you come across one. Additionally, set up a script in package.json to be able to quickly run the test suite with either npm run test or npm test.

For your unit tests, you must write:

  • 1 test containing a valid catalog
  • 1 test containing an invalid catalog
  • 2 tests containing custom catalog(s) you wrote yourself (not provided by the starter)

Since you are writing your own JSON catalogs, be sure to include these files with your submission!

Refer to the rubric at the bottom of the page on how these tests will be graded. These tests can take any form, so long as they represent an attempt to make use of Jest's features to check that validation is performed correctly.

Part 5: Style Checking

Finally, you should polish up your project and standardize the style within the project. With eslint, add 4 extra style rules beyond any recommended default rules for JavaScript and TypeScript. With prettier, add 2 extra rules beyond the defaults. This process will give you a taste of setting up style checking as part of the production pipeline of projects. Don't just copy the rules from Homework 1 (since some of them require extra dependencies), try branching out a bit and exploring how different rules work!

Submission & Rubric

README

Answer the provided reflection questions within the starter code README file. In this reflection, you will also indicate whether or not you used AI, and also document your usage of AI as well. Please don't forget this step, as it is important feedback for the homework and the content of the course!

Submission

Submit your code through Gradescope as a .zip file that contains your project. Make sure your project includes all files you worked on during this homework and your README.md file, all config files for TS, eslint, and prettier, your test script, and the every JSON file used in the tests. You should NOT include the node_modules folder in the .zip file (feel free to delete it before submission), as it is quite heavy and we will reinstall the dependencies for grading anyways. Make sure the submitted file structure within your submission is exactly or similar to the file structure you used to run and develop the project. Points will be taken off for malformed project structures in the final submission!

Since you are preparing eslint in your own, we will subject your code to your defined linting rules instead of the standard rules we would apply, so make sure you pass your own set of style rules!

Rubric

[5pts total] Your project is well organized

  • [2pts] The project is well organized and follows a reasonable file/folder structure.
  • [2pts] package.json includes:
    • A project name
    • A description
    • An author
    • A main script
    • A license
  • [1pts] Only the packages required during runtime should be listed as dependencies. The rest should be devDependencies.

[8pts total] Product Schema

  • [1pts] The script provides a complete schema for the shop's products.
  • [1pts] The script implementation must use the package zod for validation.
  • [4pts] The schema correctly represents each shop product with:
    • The common properties of each product (id, name, price, inStock, tags, seller)
    • A separate schema for a seller, which is used as part of the common properties above
    • A discriminated union using another property, category as the discriminator
    • Unique properties for each product category
  • [2pts] All properties have appropriate Zod types and validation rules.

[10pts total] Validation Function

  • [2pt] The project includes a validation function that takes a filename for a JSON file as an argument, and parses it using fs
  • [2pts] The function uses safeParse() with the product schema to validate the parsed JSON data.
  • [2pts] For successful validations, the function uses console.log() to display:
    • A success message
    • The total number of products
    • A list containing each product's ID, name, category, and one category-specific property in a single formatted string
  • [2pts] For failed validations, the function uses console.log() to display:
    • A failure message
    • A list of validation failure and their associated error messages
  • [2pt] The validation result object is returned from the function in both successful and failed cases.

[6pts total] Your project should use TypeScript.

  • [2pts] The project uses TypeScript.
  • [2pts] All application code, excluding configuration files, is written in TypeScript (.ts files).
  • [2pts] The project contains a build script in package.json that uses tsc to transpile the source code into an output directory.

[6pts total] Your project should have linting and formatting set up.

  • [3pts] eslint is installed locally and configured with a configuration file containing at least 4 additional rules beyond the recommended default rules.
  • [3pts] prettier is installed locally and configured with at least 2 non-default formatting rules.

[6pts total] Your project should have unit testing.

  • [2pts] Uses the testing suite Jest, which should should be run when you call npm test or npm run test.
  • [2pts] For your script, you must write:
    • 1 test containing a valid catalog
    • 1 test containing an invalid catalog
    • 2 tests containing custom catalog(s) you wrote yourself (not provided by the starter)
  • [2pt] Unit tests show attempts to test different validation behaviors and edge cases

[6pts total] You should include a README.md and LICENSE file.

  • [4pts] README.md has the reflection questions filled out
  • [2pts] Project contains a LICENSE file, matching the license listed in package.json (use ISC if not sure which one to pick)

[3pts] Your submitted code to Gradescope should not include node_modules. (This should mirror what would happen if you had pushed this project to a GitHub repo with node_modules in a .gitignore)