Porting the Shipping Label Script
Marta’s shop tools are moving to JavaScript, so in this project, you ported most of her Python script, and for order 1042, the port prints exactly Python’s label. The remote-area surcharge and the gift check are left for the exercise.
- The rates table keeps its home country in a variable. A bare key in a JavaScript literal is the
key’s own name, so the variable goes in brackets:
[HOME_COUNTRY]: 3.2. - The tracked countries become a Set built from an array,
new Set(["US", "CA", "AU"]). In JavaScript, braces make an object, so Python’s set literal would stop the file with a syntax error. - The paste goes between backticks: a template literal spans lines, like Python’s triple quotes.
Unlike them, a backtick inside the paste would end it, and
${would start code.JSON.parse()turns the text into an object. - Iris ticked “same as billing”, so the shipping address is
null. Python’soris||in JavaScript. The port uses??instead: it steps past onlynullandundefined, so Iris gets the Leeds billing address. - Order 1042 has no
customerblock, so the phone reads it with?., then a default,"no phone":order.customer?.phone ?? "no phone". Without?., readingphonefromundefinedwould raise aTypeErrorand stop the script. - The country is a fixed key, so it’s read with a dot. The rate’s key comes from the data, so it
goes in brackets, with the rest of the world rate as the default:
RATES[country] ?? RATES.ROW. Iris’s order gets 3.2, as in Python. In JavaScript, the table needed brackets to make"GB"a key.RATES.countrywould look for a key calledcountry, and Iris would pay 16.5, with no warning. - The tags become a Set, which drops the repeated
"gift". The label is an object literal with Python’s keys. For tracked, the Set’s.has()method answers the question: Iris’s order isn’t tracked. JavaScript’sinoperator asks about an object’s properties, not a Set’s members, so it would sayfalseeven for the US. - The parcels are the line items, counted with
.lengthwhere Python useslen(). Likelen(),.lengthcounts the line items, not the three notebooks in them, so the label gets two parcels. - The insured value keeps Iris’s
0with??.||, like Python’sor, would replace it with 50, the cover she turned down. The tags go in as an array, spread out of the Set and sorted,fragilethengift:[...tags].toSorted(). Left as a Set, it would come out empty,{}, where Python’sjson.dumps()refuses it. - The print line becomes
console.log(), withJSON.stringify()wherejson.dumps()was. With no keyword arguments, the indent goes third, afternull, which says “no replacer”:JSON.stringify(label, null, 2). A2in second place would print the label on one line.
Here’s the port, shipping-label.js, with the surcharge and the gift check still to come:
const HOME_COUNTRY = "GB";
const RATES = {
[HOME_COUNTRY]: 3.2,
IE: 7.5,
DE: 8.9,
US: 14.5,
ROW: 16.5,
};
const TRACKED_COUNTRIES = new Set(["US", "CA", "AU"]);
const ORDER_TEXT = `{
"id": 1042,
"billing_address": {
"name": "Iris Okafor",
"street": "12 Marsh Lane",
"city": "Leeds",
"postcode": "LS6 2QA",
"country": "GB"
},
"shipping_address": null,
"insured_value": 0,
"line_items": [
{ "sku": "A5-DOT", "qty": 2 },
{ "sku": "A6-LINED", "qty": 1 }
],
"tags": ["gift", "fragile", "gift"],
"total": 46.0
}`;
const order = JSON.parse(ORDER_TEXT);
const address = order.shipping_address ?? order.billing_address;
const phone = order.customer?.phone ?? "no phone";
const country = address.country;
const postage = RATES[country] ?? RATES.ROW;
const tags = new Set(order.tags);
const label = {
order: order.id,
to: address,
phone: phone,
postage: postage,
tracked: TRACKED_COUNTRIES.has(country),
parcels: order.line_items.length,
insured_value: order.insured_value ?? 50,
tags: [...tags].toSorted(),
};
console.log(JSON.stringify(label, null, 2));