Skip to content

Commit 23c52fd

Browse files
chore: Backport tooling upgrades to support WarpDrive package unification (#9755)
* chore: tooling upgrades to support WarpDrive package unification (#9752) * chore: More upgrades to monorepo tooling (#9753) * chore: update files array for types when needed * chore: improve detection of test apps * better guard * better guard * better guard * fix --------- Co-authored-by: Chris Thoburn <runspired@users.noreply.github.com>
1 parent 069e5ea commit 23c52fd

File tree

453 files changed

+13394
-581
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

453 files changed

+13394
-581
lines changed

CODE_OF_CONDUCT.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Code Of Conduct
22

3-
The `ember-data` core team and and the broader `Ember` community are committed to everyone
3+
The `warp-drive` core team and and the broader `Ember` community are committed to everyone
44
having a safe and inclusive experience.
55

66
- Our **Community Guidelines / Code of Conduct** can be found at [emberjs.com/guidelines](https://emberjs.com/guidelines/)

CONTRIBUTING.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Welcome!
44

5-
We are so glad you are considering contributing to `EmberData`. Before that, kindly take a minute to read the [Code of Conduct](https://github.com/emberjs/data/blob/main/CODE_OF_CONDUCT.md). Below you'll find links to topics
5+
We are so glad you are considering contributing to `WarpDrive`. Before that, kindly take a minute to read the [Code of Conduct](https://github.com/emberjs/data/blob/main/CODE_OF_CONDUCT.md). Below you'll find links to topics
66
detailing how to become involved to best ensure your contributions are successful!
77

88
- [Reporting Issues](./contributing/issues.md)

LICENSE.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2017-2024 Ember.js and contributors
3+
Copyright (c) 2017-2025 Ember.js and contributors
44
Copyright (c) 2011-2017 Tilde, Inc. and contributors
55
Copyright (c) 2011 LivingSocial Inc.
66

internal-tooling/README.md

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# @warp-drive/internal-tooling
2+
3+
This internal (private) project provides a number of tooling scripts
4+
for use with the monorepo.
5+
6+
These scripts can be run as bin-scripts from root.
7+
8+
## bun sync-logos
9+
10+
Will sync the logo directory from root to each public package and
11+
ensure that the logos directory is included in published files.
12+
13+
## bun sync-license
14+
15+
Will sync the LICENSE.md file from root to each public package and
16+
ensure that the license is both set to `MIT` in the package.json and
17+
included in the published files for each package.
18+
19+
## bun sync-references
20+
21+
Will ensure that `paths` and `references` are both correctly specified
22+
in tsconfig.json for any other workspace package specified by package.json
23+
as a dependency, peer-dependency, or dev-dependency.
24+
25+
Will also ensure the proper settings for composite etc. are in use.
26+
27+
For packages that should emit types (any non-test app package) it will
28+
ensure that the declarationDir is added to the files array in package.json.

internal-tooling/package.json

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "@warp-drive/internal-tooling",
3+
"version": "5.4.0-alpha.142",
4+
"description": "Internal Tooling for the WarpDrive Project Monorepo | Unpublished",
5+
"private": true,
6+
"type": "module",
7+
"files": [
8+
"src"
9+
],
10+
"bin": {
11+
"sync-logos": "src/sync-logos.ts",
12+
"sync-license": "src/sync-license.ts",
13+
"sync-references": "src/sync-references.ts"
14+
},
15+
"dependencies": {
16+
"@types/bun": "^1.2.4",
17+
"typescript": "^5.8.2",
18+
"chalk": "5.4.1",
19+
"debug": "4.4.0",
20+
"@types/debug": "4.1.12",
21+
"comment-json": "^4.2.5",
22+
"@pnpm/find-workspace-dir": "1000.1.0",
23+
"@pnpm/find-workspace-packages": "6.0.9",
24+
"@pnpm/logger": "1000.0.0"
25+
},
26+
"engines": {
27+
"node": ">= 18.20.7"
28+
},
29+
"volta": {
30+
"extends": "../package.json"
31+
}
32+
}

internal-tooling/src/-utils.ts

+201
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
import type { BunFile } from 'bun';
2+
import path from 'path';
3+
import type { CommentObject } from 'comment-json';
4+
import { findWorkspaceDir } from '@pnpm/find-workspace-dir';
5+
import { findWorkspacePackages, type Project } from '@pnpm/find-workspace-packages';
6+
7+
export async function getMonorepoRoot() {
8+
const workspaceDir = await findWorkspaceDir(process.cwd());
9+
10+
if (workspaceDir) {
11+
return workspaceDir;
12+
}
13+
14+
const MAX_DEPTH = 10;
15+
// are we in the root?
16+
let currentDir = process.cwd();
17+
let depth = 0;
18+
while (depth < MAX_DEPTH) {
19+
const lockfileFile = path.join(currentDir, 'pnpm-lock.yaml');
20+
if (await Bun.file(lockfileFile).exists()) {
21+
return currentDir;
22+
}
23+
currentDir = path.join(currentDir, '../');
24+
depth++;
25+
}
26+
27+
throw new Error(`Could not find monorepo root from cwd ${process.cwd()}`);
28+
}
29+
30+
export async function getPackageJson({ packageDir, packagesDir }: { packageDir: string; packagesDir: string }) {
31+
const packageJsonPath = path.join(packagesDir, packageDir, 'package.json');
32+
const packageJsonFile = Bun.file(packageJsonPath);
33+
const pkg = await packageJsonFile.json();
34+
return { file: packageJsonFile, pkg, path: packageJsonPath, nicePath: path.join(packageDir, 'package.json') };
35+
}
36+
37+
export async function runPrettier() {
38+
const root = await getMonorepoRoot();
39+
const childProcess = Bun.spawn(['bun', 'lint:prettier:fix'], {
40+
env: process.env,
41+
cwd: root,
42+
stdout: 'inherit',
43+
stderr: 'inherit',
44+
});
45+
await childProcess.exited;
46+
}
47+
48+
type PkgJsonFile = {
49+
name: string;
50+
version: string;
51+
files?: string[];
52+
license?: string;
53+
private?: boolean;
54+
dependencies?: Record<string, string>;
55+
devDependencies?: Record<string, string>;
56+
peerDependencies?: Record<string, string>;
57+
scripts?: Record<string, string>;
58+
main?: string;
59+
peerDependenciesMeta?: Record<string, { optional: boolean }>;
60+
};
61+
62+
export type TsConfigFile = {
63+
include?: string[];
64+
compilerOptions?: {
65+
lib?: string[];
66+
module?: string;
67+
target?: string;
68+
moduleResolution?: string;
69+
moduleDetection?: string;
70+
erasableSyntaxOnly?: boolean;
71+
allowImportingTsExtensions?: boolean;
72+
verbatimModuleSyntax?: boolean;
73+
isolatedModules?: boolean;
74+
isolatedDeclarations?: boolean;
75+
pretty?: boolean;
76+
strict?: boolean;
77+
experimentalDecorators?: boolean;
78+
allowJs?: boolean;
79+
checkJs?: boolean;
80+
rootDir?: string;
81+
baseUrl?: string;
82+
declarationMap?: boolean;
83+
inlineSourceMap?: boolean;
84+
inlineSources?: boolean;
85+
skipLibCheck?: boolean;
86+
declaration?: boolean;
87+
declarationDir?: string;
88+
incremental?: boolean;
89+
composite?: boolean;
90+
emitDeclarationOnly?: boolean;
91+
noEmit?: boolean;
92+
paths?: Record<string, string[]>;
93+
types?: string[];
94+
};
95+
references?: { path: string }[];
96+
};
97+
98+
interface BaseProjectPackage {
99+
project: Project;
100+
packages: Map<string, Project>;
101+
pkgFile: BunFile;
102+
tsconfigFile: BunFile;
103+
pkgPath: string;
104+
tsconfigPath: string;
105+
isRoot: boolean;
106+
isPrivate: boolean;
107+
isTooling: boolean;
108+
isConfig: boolean;
109+
isTest: boolean;
110+
pkg: PkgJsonFile;
111+
save: (editStatus: { pkgEdited: boolean; configEdited: Boolean }) => Promise<void>;
112+
}
113+
114+
export interface ProjectPackageWithTsConfig extends BaseProjectPackage {
115+
tsconfig: CommentObject & TsConfigFile;
116+
hasTsConfig: true;
117+
}
118+
119+
interface ProjectPackageWithoutTsConfig extends BaseProjectPackage {
120+
tsconfig: null;
121+
hasTsConfig: false;
122+
}
123+
124+
export type ProjectPackage = ProjectPackageWithTsConfig | ProjectPackageWithoutTsConfig;
125+
126+
async function collectAllPackages(dir: string) {
127+
const packages = await findWorkspacePackages(dir);
128+
const pkgMap = new Map<string, Project>();
129+
for (const pkg of packages) {
130+
if (!pkg.manifest.name) {
131+
throw new Error(`Package at ${pkg.dir} does not have a name`);
132+
}
133+
pkgMap.set(pkg.manifest.name, pkg);
134+
}
135+
136+
return pkgMap;
137+
}
138+
139+
export async function walkPackages(
140+
cb: (pkg: ProjectPackage, projects: Map<string, ProjectPackage>) => void | Promise<void>,
141+
options: {
142+
excludeTests?: boolean;
143+
excludePrivate?: boolean;
144+
excludeRoot?: boolean;
145+
excludeTooling?: boolean;
146+
excludeConfig?: boolean;
147+
} = {}
148+
) {
149+
const config = Object.assign(
150+
{ excludeTests: false, excludePrivate: false, excludeRoot: true, excludeTooling: true, excludeConfig: true },
151+
options
152+
);
153+
const JSONC = await import('comment-json');
154+
const dir = await getMonorepoRoot();
155+
const packages = await collectAllPackages(dir);
156+
const projects = new Map<string, ProjectPackageWithTsConfig>();
157+
const TestDir = path.join(dir, 'tests');
158+
159+
for (const [name, project] of packages) {
160+
if (config.excludeRoot && name === 'root') continue;
161+
if (config.excludePrivate && project.manifest.private) continue;
162+
if (config.excludeTooling && name === '@warp-drive/internal-tooling') continue;
163+
if (config.excludeConfig && name === '@warp-drive/config') continue;
164+
if (config.excludeTests && project.dir.startsWith(TestDir)) continue;
165+
166+
const pkgPath = path.join(project.dir, 'package.json');
167+
const tsconfigPath = path.join(project.dir, 'tsconfig.json');
168+
const pkgFile = Bun.file(pkgPath);
169+
const tsconfigFile = Bun.file(tsconfigPath);
170+
const pkg = (await pkgFile.json()) as PkgJsonFile;
171+
const hasTsConfig = await tsconfigFile.exists();
172+
const tsconfig = hasTsConfig ? (JSONC.parse(await tsconfigFile.text()) as CommentObject & TsConfigFile) : null;
173+
174+
const pkgObj = {
175+
project,
176+
packages,
177+
pkgFile,
178+
tsconfigFile,
179+
pkgPath,
180+
hasTsConfig,
181+
tsconfigPath,
182+
isRoot: name === 'root',
183+
isPrivate: project.manifest.private ?? false,
184+
isTooling: name === '@warp-drive/internal-tooling',
185+
isConfig: name === '@warp-drive/config',
186+
isTest: project.dir.startsWith(TestDir),
187+
pkg,
188+
tsconfig,
189+
save: async ({ pkgEdited, configEdited }: { pkgEdited: boolean; configEdited: Boolean }) => {
190+
if (pkgEdited) await pkgFile.write(JSON.stringify(pkg, null, 2));
191+
if (configEdited) await tsconfigFile.write(JSONC.stringify(tsconfig, null, 2));
192+
},
193+
} as ProjectPackageWithTsConfig;
194+
195+
projects.set(name, pkgObj);
196+
}
197+
198+
for (const project of projects.values()) {
199+
await cb(project, projects);
200+
}
201+
}

internal-tooling/src/sync-license.ts

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#! /usr/bin/env bun
2+
3+
import path from 'path';
4+
import fs from 'fs';
5+
import debug from 'debug';
6+
import chalk from 'chalk';
7+
import type { BunFile } from 'bun';
8+
import { getMonorepoRoot, getPackageJson } from './-utils';
9+
10+
const log = debug('wd:sync-license');
11+
12+
async function updatePackageJson({ pkg, file, nicePath }: { pkg: any; file: BunFile; path: string; nicePath: string }) {
13+
let edited = false;
14+
// ensure "files" field in package.json includes "LICENSE.md"
15+
if (!pkg.files) {
16+
pkg.files = ['LICENSE.md'];
17+
edited = true;
18+
log(`\t\t📝 Added "LICENSE.md" to "files" in ${nicePath}`);
19+
} else if (!pkg.files.includes('LICENSE.md')) {
20+
pkg.files.push('LICENSE.md');
21+
edited = true;
22+
log(`\t\t📝 Added "LICENSE.md" to "files" in ${nicePath}`);
23+
}
24+
25+
if (pkg.license !== 'MIT') {
26+
pkg.license = 'MIT';
27+
edited = true;
28+
log(`\t\t⚖️ Updated "license" to "MIT" in ${nicePath}`);
29+
}
30+
31+
if (edited) {
32+
await file.write(JSON.stringify(pkg, null, 2));
33+
}
34+
}
35+
36+
async function main() {
37+
log(
38+
`\n\t${chalk.gray('=').repeat(60)}\n\t\t${chalk.magentaBright('@warp-drive/')}${chalk.greenBright('internal-tooling')} Sync LICENSE.md\n\t${chalk.gray('=').repeat(60)}\n\n\t\t${chalk.gray(`Syncing LICENSE.md from monorepo root to each public package`)}\n\n`
39+
);
40+
const monorepoRoot = await getMonorepoRoot();
41+
42+
// sync the LICENSE.md file from the monorepo root to each
43+
// public package
44+
45+
const licenseFilePath = path.join(monorepoRoot, 'LICENSE.md');
46+
const packagesDir = path.join(monorepoRoot, 'packages');
47+
48+
for (const packageDir of fs.readdirSync(packagesDir)) {
49+
const details = await getPackageJson({ packageDir, packagesDir });
50+
51+
if (details.pkg.private) {
52+
log(`\t\t🔒 Skipping private package ${details.nicePath}`);
53+
continue;
54+
}
55+
56+
const packageFullDir = path.join(packagesDir, packageDir);
57+
const packageLicensePath = path.join(packageFullDir, 'LICENSE.md');
58+
59+
// remove th existing LICENSE.md file if it exists
60+
if (fs.existsSync(packageLicensePath)) {
61+
fs.rmSync(packageLicensePath);
62+
log(`\t\t💨 Deleted existing LICENSE.md in ${packageDir}`);
63+
}
64+
65+
fs.copyFileSync(licenseFilePath, packageLicensePath);
66+
log(`\t\t⚖️ Copied LICENSE.md to ${packageDir}`);
67+
68+
await updatePackageJson(details);
69+
70+
log('\n');
71+
}
72+
}
73+
74+
main();

0 commit comments

Comments
 (0)