Skip to content

Commit 0026fbf

Browse files
authored
Merge pull request #320 from danielpza/@tsconfig/bases
feat: add @tsconfig/bases
2 parents 5a0cc81 + 8ed9136 commit 0026fbf

File tree

8 files changed

+201
-0
lines changed

8 files changed

+201
-0
lines changed

.github/workflows/CI.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@ jobs:
2020
- name: Create packages for TSConfig JSONs
2121
run: deno run --allow-read --allow-write --allow-net scripts/create-npm-packages.ts
2222

23+
- name: Test
24+
working-directory: test/
25+
run: |
26+
corepack enable
27+
pnpm install
28+
pnpm test
29+
2330
- name: Update the README
2431
run: deno run --allow-read --allow-write --allow-net scripts/update-markdown-readme.ts
2532

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
*.log
22
packages/
33
.idea/
4+
node_modules

scripts/create-npm-packages.ts

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ for await (const tsconfigEntry of Deno.readDir("bases")) {
1515
const templateDir = "./template"
1616
for await (const templateFile of Deno.readDir(templateDir)) {
1717
if (!templateFile.isFile) continue
18+
if (templateFile.name === "README-combined.md") continue // README-combined.md is only for the combined bases
1819
const templatedFile = path.join(templateDir, templateFile.name)
1920
Deno.copyFileSync(templatedFile, path.join(packagePath, templateFile.name))
2021
}
@@ -90,6 +91,8 @@ for await (const tsconfigEntry of Deno.readDir("bases")) {
9091
console.log("Built:", tsconfigEntry.name);
9192
}
9293

94+
await buildTsconfigBases()
95+
9396
function isBumpedVersionHigher (packageJSONVersion: string, bumpedVersion: string) {
9497
const semverMarkersPackageJSON = packageJSONVersion.split('.')
9598
const semverMarkersBumped = bumpedVersion.split('.')
@@ -101,3 +104,118 @@ function isBumpedVersionHigher (packageJSONVersion: string, bumpedVersion: strin
101104

102105
return true
103106
}
107+
108+
// build @tsconfig/bases catch all package
109+
async function buildTsconfigBases() {
110+
const name = "bases"
111+
112+
// Make the folder
113+
const packagePath = path.join("packages", name)
114+
Deno.mkdirSync(packagePath, { recursive: true })
115+
116+
// Copy over the template files
117+
const templateDir = "./template"
118+
for await (const templateFile of Deno.readDir(templateDir)) {
119+
if (!templateFile.isFile) continue
120+
if (templateFile.name === "README.md") continue
121+
const templatedFile = path.join(templateDir, templateFile.name)
122+
Deno.copyFileSync(
123+
templatedFile,
124+
path.join(
125+
packagePath,
126+
templateFile.name === "README-combined.md" ? "README.md" : templateFile.name,
127+
),
128+
)
129+
}
130+
131+
const exportsOverride = {}
132+
133+
// Copy the tsconfig.json files from all bases
134+
for await (const tsconfigEntry of Deno.readDir("bases")) {
135+
if (!tsconfigEntry.isFile) continue
136+
137+
// remove extension
138+
const name = tsconfigEntry.name.replace(/\.json$/, "")
139+
140+
const finalTsconfigFile = `${name}.tsconfig.json`
141+
142+
// add entry to package.json exports
143+
exportsOverride[`./${name}`] = `./${finalTsconfigFile}`
144+
145+
const tsconfigFilePath = path.join("bases", tsconfigEntry.name)
146+
147+
const newPackageTSConfigPath = path.join(packagePath, finalTsconfigFile)
148+
149+
Deno.copyFileSync(tsconfigFilePath, newPackageTSConfigPath)
150+
151+
const tsconfigText = await Deno.readTextFile(newPackageTSConfigPath)
152+
153+
// Drop `display` field in tsconfig.json for npm package
154+
await Deno.writeTextFile(newPackageTSConfigPath, tsconfigText.replace(/\s*"display.*/, ""))
155+
}
156+
157+
const tsconfigJSON = { display: "Bases" }
158+
159+
// Edit the package.json
160+
const packageText = await Deno.readTextFile(path.join(packagePath, "package.json"))
161+
const packageJSON = JSON.parse(packageText)
162+
packageJSON.name = `@tsconfig/${name}`
163+
packageJSON.description = `Combined tsconfig bases.`
164+
packageJSON.keywords = ["tsconfig", name, "combined"]
165+
packageJSON.exports = exportsOverride
166+
167+
// Do some string replacements in the other templated files
168+
const replaceTextIn = ["README.md"]
169+
for (const filenameToEdit of replaceTextIn) {
170+
const fileToEdit = path.join(packagePath, filenameToEdit)
171+
172+
const defaultTitle = `A base TSConfig for working with ${tsconfigJSON.display}`
173+
const title = name !== "recommended" ? defaultTitle : "The recommended base for a TSConfig"
174+
175+
let packageText = await Deno.readTextFile(fileToEdit)
176+
packageText = packageText.replace(/\[filename\]/g, name).replace(/\[display_title\]/g, title)
177+
178+
// Inject readme-extra if any
179+
try {
180+
const readmeExtra = (await Deno.readTextFile(path.join("readme-extras", `${name}.md`))).trim()
181+
182+
if (readmeExtra) {
183+
packageText = packageText.replace(/\[readme-extra\]/g, `\n${readmeExtra}\n`)
184+
}
185+
} catch (error) {
186+
// NOOP, there is no extra readme
187+
// console.log(error)
188+
}
189+
190+
// Remove readme-extra placeholders if any
191+
packageText = packageText.replace(/\[readme-extra\]/g, "")
192+
193+
await Deno.writeTextFile(fileToEdit, packageText)
194+
}
195+
196+
// Bump the last version of the number from npm,
197+
// or use the _version in tsconfig if it's higher,
198+
// or default to 1.0.0
199+
let version = tsconfigJSON._version || "1.0.0"
200+
try {
201+
const npmResponse = await fetch(`https://registry.npmjs.org/${packageJSON.name}`)
202+
const npmPackage = await npmResponse.json()
203+
204+
const semverMarkers = npmPackage["dist-tags"].latest.split(".")
205+
const bumpedVersion = `${semverMarkers[0]}.${semverMarkers[1]}.${Number(semverMarkers[2]) + 1}`
206+
if (isBumpedVersionHigher(version, bumpedVersion)) {
207+
version = bumpedVersion
208+
}
209+
} catch (error) {
210+
// NOOP, this is for the first deploy
211+
// console.log(error)
212+
}
213+
214+
packageJSON.version = version
215+
await Deno.writeTextFile(
216+
path.join(packagePath, "package.json"),
217+
JSON.stringify(packageJSON, null, " "),
218+
)
219+
220+
console.log("Built:", "bases")
221+
}

template/README-combined.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
### [display_title].
2+
3+
Add the package to your `"devDependencies"`:
4+
5+
```sh
6+
npm install --save-dev @tsconfig/[filename]
7+
yarn add --dev @tsconfig/[filename]
8+
```
9+
10+
Add to your `tsconfig.json`:
11+
12+
```json
13+
"extends": "@tsconfig/[filename]/<base>"
14+
# eg "extends": "@tsconfig/[filename]/node-lts"
15+
```
16+
17+
You can find the [code here](https://github.com/tsconfig/bases/blob/master/bases/).

test/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log("Hello World")

test/package.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "test-bases",
3+
"scripts": {
4+
"test": "tsc --noEmit"
5+
},
6+
"packageManager": "[email protected]",
7+
"devDependencies": {
8+
"@tsconfig/bases": "link:../packages/bases",
9+
"@types/node": "^24.2.1",
10+
"typescript": "^5.9.2"
11+
}
12+
}

test/pnpm-lock.yaml

Lines changed: 42 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/tsconfig.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": ["@tsconfig/bases/node-lts"]
3+
}

0 commit comments

Comments
 (0)