Skip to content

Commit

Permalink
I think it works
Browse files Browse the repository at this point in the history
  • Loading branch information
NullVoxPopuli committed Jan 28, 2024
1 parent 3eeb6cc commit d16acd1
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 97 deletions.
16 changes: 5 additions & 11 deletions src/-tests/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import type { Config } from '../types.js';
import { normalizeConfig } from '../config.js';

export function c(overrides: Partial<Config> = {}): Config {
return {
'write-as': 'pinned' as const,
...overrides,
'update-range': {
'~': [],
'^': [],
...overrides['update-range'],
},
};
import type { Config, UserConfig } from '../types.js';

export function c(userConfig: UserConfig = {}): Config {
return normalizeConfig(userConfig);
}
54 changes: 54 additions & 0 deletions src/config-getOverride.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { describe, expect as e, it } from 'vitest';

import { c } from './-tests/helpers.ts';
import { getOverride } from './config.js';

const expect = e.soft;

describe('getOverride', () => {
it('resolves a package glob', () => {
expect(
getOverride(
'packages/ember-repl/addon',
c({
overrides: [
{
path: [
'packages/*/addon/package.json',
'packages/syntax/*/package.json',
],
dependencies: false,
devDependencies: 'pinned',
},
],
}),
),
).toMatchInlineSnapshot(`
{
"dependencies": false,
"devDependencies": "pinned",
"path": [
"packages/*/addon/package.json",
"packages/syntax/*/package.json",
],
}
`);
});

it('returns nothing when no match is found', () => {
expect(
getOverride(
'apps/repl',
c({
overrides: [
{
path: ['packages/*/addon/package.json'],
dependencies: false,
devDependencies: 'pinned',
},
],
}),
),
).toBe(undefined);
});
});
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, expect as e, it } from 'vitest';

import { normalizeConfig } from './utils.js';
import { normalizeConfig } from './config.js';

const expect = e.soft;

Expand All @@ -19,7 +19,7 @@ describe('normalizeConfig', () => {
});

it('overrides "write-as"', () => {
expect(normalizeConfig({ 'write-as': "minors" })).toMatchInlineSnapshot(`
expect(normalizeConfig({ 'write-as': 'minors' })).toMatchInlineSnapshot(`
{
"overrides": [],
"update-range": {
Expand All @@ -32,15 +32,17 @@ describe('normalizeConfig', () => {
});

it('specifies overrides', () => {
expect(normalizeConfig({
overrides: [
{
path: 'x/y/z',
devDependencies: false,
dependencies: false,
}
]
})).toMatchInlineSnapshot(`
expect(
normalizeConfig({
overrides: [
{
path: 'x/y/z',
devDependencies: false,
dependencies: false,
},
],
}),
).toMatchInlineSnapshot(`
{
"overrides": [
{
Expand All @@ -61,16 +63,14 @@ describe('normalizeConfig', () => {
});

it('specifies update-range', () => {
expect(normalizeConfig({
'update-range': {
'~': [
'ember-data',
],
'^': [
'@ember-data/*'
],
}
})).toMatchInlineSnapshot(`
expect(
normalizeConfig({
'update-range': {
'~': ['ember-data'],
'^': ['@ember-data/*'],
},
}),
).toMatchInlineSnapshot(`
{
"overrides": [],
"update-range": {
Expand Down
56 changes: 56 additions & 0 deletions src/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import path from 'node:path';

import { minimatch } from 'minimatch';

/**
* @param {Partial<import('./types.ts').UserConfig>} [ userConfig ]
* @return {import('./types.ts').Config}
*/
export function normalizeConfig(userConfig) {
let config = userConfig || {};

let topLevel = {
'write-as': config['write-as'] || 'pinned',
};

/** @type {import('./types.ts').Config['overrides'] } */
const overrides =
config['overrides']?.map((override) => {
const defaultRange = topLevel['write-as'];
const pathsArray = Array.isArray(override.path)
? override.path
: [override.path];

return {
devDependencies: override['devDependencies'] ?? defaultRange,
dependencies: override['dependencies'] ?? defaultRange,
path: pathsArray,
};
}) || [];

return {
...topLevel,
'update-range': {
'~': [],
'^': [],
...config['update-range'],
},
overrides,
};
}

/**
* @param {string} relativePath the workspace path
* @param {import('./types.ts').Config} config
*/
export function getOverride(relativePath, config) {
let { overrides } = config;

let packageJsonPath = path.join(relativePath, 'package.json');

let override = overrides.find((override) => {
return override.path.some((match) => minimatch(packageJsonPath, match));
});

return override;
}
68 changes: 48 additions & 20 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { cosmiconfig } from 'cosmiconfig';
import debug from 'debug';
import { packageJson, project } from 'ember-apply';

import { injestDeps, normalizeConfig, updateManifestFor } from './utils.js';
import { getOverride, normalizeConfig } from './config.js';
import { injestDeps, updateManifestFor } from './utils.js';

const d = debug('defrag');
const configExplorer = cosmiconfig('defrag');
Expand All @@ -28,35 +29,62 @@ export default async function run() {
d(`Resolved config:`);
d(config);

let manifests = [
projectResult.rootPackage?.packageJson,
...projectResult.packages.map((p) => p.packageJson),
].filter(Boolean);
let packages = [projectResult.rootPackage, ...projectResult.packages].filter(
Boolean,
);

d(`Found ${manifests.length} packages`);
manifests.forEach((p) => p && injestDeps(p));
d(`Found ${packages.length} packages`);
packages.forEach((p) => p && injestDeps(p.packageJson));

let paths = [
projectResult.rootPackage?.dir,
...projectResult.packages.map((p) => p.dir),
].filter(Boolean);
for (const pkg of packages) {
if (!pkg) continue;

d(`Found ${paths.length} paths`);

for (let projectPath of paths) {
if (!projectPath) continue;

d(`Updating ${projectPath.replace(root, '')}`);
d(`Updating ${pkg.relativeDir}`);

await packageJson.modify((manifest) => {
updateManifestFor(manifest.devDependencies, config);
updateManifestFor(manifest.dependencies, config);
// These have configurable overrides in .defragrc.yml
update(manifest, pkg.relativeDir, config, 'devDependencies');
update(manifest, pkg.relativeDir, config, 'dependencies');

// These don't have configurable overrides as they
// *are* the overrides for the whole repo
// (or in some cases a single workspace)
// In any case, they only affect local development,
// and not versions used by a consumer in a published package.
//
// npm
updateManifestFor(manifest.overrides, config);
// yarn
updateManifestFor(manifest.resolutions, config);
// pnpm
updateManifestFor(manifest.pnpm?.overrides, config);
}, projectPath);
}, pkg.dir);
}
}

/**
* @param {Record<string, any>} manifest
* @param {string} relativePath
* @param {import('./types.ts').Config} config
* @param {'devDependencies' | 'dependencies'} collection
*/
function update(manifest, relativePath, config, collection) {
let override = getOverride(relativePath, config);

if (!override) {
return updateManifestFor(manifest[collection], config);
}

let collectionConfig = override[collection];

if (collectionConfig === false) {
return;
}

let writeAs = collectionConfig ?? config['write-as'];

updateManifestFor(manifest[collection], {
'write-as': writeAs,
'update-range': config['update-range'],
});
}
7 changes: 4 additions & 3 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ export type Manifest = Package['packageJson'];

type Range = 'pinned' | 'minors' | 'patches';

export type ConfigForUpdate = Pick<Config, 'write-as' | 'update-range'>;

export interface Config {
'write-as': Range;
'update-range': {
Expand All @@ -16,10 +18,9 @@ export interface Config {
path: string[];
devDependencies: Range | false;
dependencies: Range | false;
}[]
}[];
}


export interface UserConfig {
'write-as'?: Range;
'update-range'?: {
Expand All @@ -30,5 +31,5 @@ export interface UserConfig {
path: string | string[];
devDependencies?: Range | false;
dependencies?: Range | false;
}[]
}[];
}
Loading

0 comments on commit d16acd1

Please sign in to comment.