@@ -10,7 +10,7 @@ import {
1010 writeJSONWithComments ,
1111} from "helpers/json" ;
1212import TOML from "smol-toml" ;
13- import type { CommentObject } from "comment-json" ;
13+ import type { CommentObject , Reviver } from "comment-json" ;
1414import type { C3Context } from "types" ;
1515
1616/**
@@ -22,6 +22,7 @@ import type { C3Context } from "types";
2222 * - adding comments with links to documentation for common configuration options
2323 * - substituting placeholders with actual values
2424 * - `<WORKER_NAME>` with the project name
25+ * - `<COMPATIBILITY_DATE>` with the max compatibility date of the installed worked
2526 *
2627 * If both `wrangler.toml` and `wrangler.json`/`wrangler.jsonc` are present, only
2728 * the `wrangler.json`/`wrangler.jsonc` file will be updated.
@@ -30,10 +31,15 @@ export const updateWranglerConfig = async (ctx: C3Context) => {
3031 // Placeholders to replace in the wrangler config files
3132 const substitutions : Record < string , string > = {
3233 "<WORKER_NAME>" : ctx . project . name ,
34+ "<COMPATIBILITY_DATE>" : await getWorkerdCompatibilityDate ( ) ,
3335 } ;
3436
35- if ( wranglerJsonExists ( ctx ) ) {
36- let wranglerJson = readWranglerJson ( ctx ) ;
37+ if ( wranglerJsonOrJsoncExists ( ctx ) ) {
38+ let wranglerJson = readWranglerJsonOrJsonc ( ctx , ( _key , value ) =>
39+ typeof value === "string" && value in substitutions
40+ ? substitutions [ value ]
41+ : value ,
42+ ) ;
3743
3844 // Put the schema at the top of the file
3945 wranglerJson = insertJSONProperty (
@@ -46,7 +52,7 @@ export const updateWranglerConfig = async (ctx: C3Context) => {
4652 wranglerJson = appendJSONProperty (
4753 wranglerJson ,
4854 "compatibility_date" ,
49- await getCompatibilityDate ( wranglerJson ) ,
55+ await getCompatibilityDate ( wranglerJson . compatibility_date ) ,
5056 ) ;
5157 wranglerJson = appendJSONProperty ( wranglerJson , "observability" , {
5258 enabled : true ,
@@ -84,20 +90,17 @@ export const updateWranglerConfig = async (ctx: C3Context) => {
8490 } ,
8591 ] ) ;
8692
87- writeWranglerJson ( ctx , wranglerJson , ( _key , value ) =>
88- typeof value === "string" && value in substitutions
89- ? substitutions [ value ]
90- : value ,
91- ) ;
93+ writeWranglerJsonOrJsonc ( ctx , wranglerJson ) ;
9294 addVscodeConfig ( ctx ) ;
9395 } else if ( wranglerTomlExists ( ctx ) ) {
94- const wranglerTomlStr = readWranglerToml ( ctx ) ;
95- const parsed = TOML . parse ( wranglerTomlStr ) ;
96- parsed . name = ctx . project . name ;
97- parsed [ "compatibility_date" ] = await getCompatibilityDate ( parsed ) ;
98- parsed [ "observability" ] ??= { enabled : true } ;
96+ const wranglerToml = TOML . parse ( readWranglerToml ( ctx ) ) ;
97+ wranglerToml . name = ctx . project . name ;
98+ wranglerToml . compatibility_date = await getCompatibilityDate (
99+ wranglerToml . compatibility_date ,
100+ ) ;
101+ wranglerToml . observability ??= { enabled : true } ;
99102
100- let strToml = TOML . stringify ( parsed ) ;
103+ let strToml = TOML . stringify ( wranglerToml ) ;
101104
102105 for ( const [ key , value ] of Object . entries ( substitutions ) ) {
103106 strToml = strToml . replaceAll ( key , value ) ;
@@ -161,8 +164,8 @@ export const wranglerTomlExists = (ctx: C3Context) => {
161164 return existsSync ( wranglerTomlPath ) ;
162165} ;
163166
164- /** Checks for wrangler.json and wrangler.jsonc */
165- export const wranglerJsonExists = ( ctx : C3Context ) => {
167+ /** Checks for an existing ` wrangler.json` or ` wrangler.jsonc` */
168+ export const wranglerJsonOrJsoncExists = ( ctx : C3Context ) => {
166169 const wranglerJsonPath = getWranglerJsonPath ( ctx ) ;
167170 const wranglerJsoncPath = getWranglerJsoncPath ( ctx ) ;
168171 return existsSync ( wranglerJsonPath ) || existsSync ( wranglerJsoncPath ) ;
@@ -173,13 +176,25 @@ export const readWranglerToml = (ctx: C3Context) => {
173176 return readFile ( wranglerTomlPath ) ;
174177} ;
175178
176- export const readWranglerJson = ( ctx : C3Context ) => {
179+ /**
180+ * Reads the JSON configuration file for this project.
181+ *
182+ * If both `wrangler.json` and `wrangler.jsonc` are present, `wrangler.json` will be read.
183+ *
184+ * @param ctx The C3 context.
185+ * @param reviver A function that transforms the results. This function is called for each member of the object.
186+ * @returns The parsed JSON object with comments.
187+ */
188+ export const readWranglerJsonOrJsonc = (
189+ ctx : C3Context ,
190+ reviver ?: Reviver | null ,
191+ ) : CommentObject => {
177192 const wranglerJsonPath = getWranglerJsonPath ( ctx ) ;
178193 if ( existsSync ( wranglerJsonPath ) ) {
179- return readJSONWithComments ( wranglerJsonPath ) ;
194+ return readJSONWithComments ( wranglerJsonPath , reviver ) ;
180195 }
181196 const wranglerJsoncPath = getWranglerJsoncPath ( ctx ) ;
182- return readJSONWithComments ( wranglerJsoncPath ) ;
197+ return readJSONWithComments ( wranglerJsoncPath , reviver ) ;
183198} ;
184199
185200export const writeWranglerToml = ( ctx : C3Context , contents : string ) => {
@@ -199,7 +214,7 @@ export const writeWranglerToml = (ctx: C3Context, contents: string) => {
199214 * an array of strings and numbers that acts as an approved list for selecting
200215 * the object properties that will be stringified.
201216 */
202- export const writeWranglerJson = (
217+ export const writeWranglerJsonOrJsonc = (
203218 ctx : C3Context ,
204219 config : CommentObject ,
205220 replacer ?:
@@ -234,25 +249,23 @@ export const addVscodeConfig = (ctx: C3Context) => {
234249} ;
235250
236251/**
237- * Gets the compatibility date to use from the wrangler config .
252+ * Gets the compatibility date to use.
238253 *
239- * If the compatibility date is missing or invalid , it sets it to the latest workerd date.
254+ * If the tentative date is valid , it is returned. Otherwise the latest workerd date is used .
240255 *
241- * @param config Wrangler config
256+ * @param tentativeDate A tentative compatibility date, usually from wrangler config.
242257 * @returns The compatibility date to use in the form "YYYY-MM-DD"
243258 */
244- async function getCompatibilityDate < T extends Record < string , unknown > > (
245- config : T ,
246- ) : Promise < string > {
259+ async function getCompatibilityDate ( tentativeDate : unknown ) : Promise < string > {
247260 const validCompatDateRe = / ^ \d { 4 } - \d { 2 } - \d { 2 } $ / m;
248- const dateFromConfig = config [ "compatibility_date" ] ;
249261 if (
250- typeof dateFromConfig === "string" &&
251- dateFromConfig . match ( validCompatDateRe )
262+ typeof tentativeDate === "string" &&
263+ tentativeDate . match ( validCompatDateRe )
252264 ) {
253- // If the compat date is already a valid one, leave it since it may be there for a specific compat reason
254- return dateFromConfig ;
265+ // Use the tentative date when it is valid.
266+ // It may be there for a specific compat reason
267+ return tentativeDate ;
255268 }
256- // If the compat date is missing or invalid, set it to the latest workerd date
269+ // Fallback to the latest workerd date
257270 return await getWorkerdCompatibilityDate ( ) ;
258271}
0 commit comments