Skip to content

Commit 6377218

Browse files
committed
chore: add basic project constraints
1 parent 0dadda4 commit 6377218

File tree

3 files changed

+195
-0
lines changed

3 files changed

+195
-0
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@
146146
"@web/test-runner-playwright": "^0.11.0",
147147
"@web/test-runner-visual-regression": "^0.9.0",
148148
"@webcomponents/webcomponentsjs": "^2.8.0",
149+
"@yarnpkg/types": "^4.0.1",
149150
"alex": "^11.0.1",
150151
"cem-plugin-module-file-extensions": "^0.0.5",
151152
"chromatic": "^11.20.0",

yarn.config.cjs

+184
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
/* eslint-disable @typescript-eslint/no-var-requires */
2+
/*!
3+
* Copyright 2025 Adobe. All rights reserved.
4+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License. You may obtain a copy
6+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software distributed under
9+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
10+
* OF ANY KIND, either express or implied. See the License for the specific language
11+
* governing permissions and limitations under the License.
12+
*/
13+
14+
/** @type {import('@yarnpkg/types')} */
15+
const { defineConfig } = require('@yarnpkg/types');
16+
const fg = require('fast-glob');
17+
18+
/**
19+
* The workspace object used in the constraints function
20+
* @typedef {import('@yarnpkg/types').Yarn.Constraints.Workspace} Workspace
21+
*/
22+
23+
module.exports = defineConfig({
24+
async constraints({ Yarn }) {
25+
/**
26+
* Fetch a list of all the component workspaces using a glob pattern
27+
* @type {string[]} components
28+
*/
29+
const components = fg.sync('packages/*', {
30+
cwd: __dirname,
31+
onlyDirectories: true,
32+
});
33+
34+
/**
35+
* This function checks the workspace for any local package references
36+
* and ensure that the devDependencies are up-to-date with the latest version
37+
* currently in the project
38+
* @param {Workspace} workspace
39+
* @returns {void}
40+
*/
41+
function validateLocalPackages(workspace) {
42+
// Return early if the workspace does not have any peerDependencies
43+
if (!workspace.manifest.peerDependencies) {
44+
return;
45+
}
46+
47+
// Start by filtering out the local packages from the external dependencies
48+
const localPackages = Object.keys(
49+
workspace.manifest.peerDependencies
50+
)
51+
.filter((pkg) => Yarn.workspace({ ident: pkg }))
52+
.map((pkg) => Yarn.workspace({ ident: pkg }));
53+
54+
// Iterate over the local packages and ensure that the devDependencies are up-to-date
55+
for (const localWorkspace of localPackages) {
56+
const localVersion = localWorkspace.manifest.version;
57+
workspace.set(
58+
`devDependencies.${localWorkspace.manifest.name}`,
59+
localVersion ?? 'workspace:^'
60+
);
61+
}
62+
}
63+
64+
/**
65+
* A reusable function to add keywords to ensure workspaces
66+
* include a minimal set of keywords for discoverability
67+
* with additionalKeywords as an optional parameter to add more
68+
* specific keywords that are relevant to the workspace
69+
* @param {string[]} additionalKeywords
70+
* @returns {string[]}
71+
*/
72+
function keywords(additionalKeywords = []) {
73+
return [
74+
'design-system',
75+
'spectrum',
76+
'adobe',
77+
'adobe-spectrum',
78+
'web components',
79+
'web-components',
80+
'lit-element',
81+
'lit-html',
82+
...additionalKeywords,
83+
];
84+
}
85+
86+
/**
87+
* This function rolls up all the component package.json
88+
* requirements for all workspaces into a single function
89+
* to simplify into a readable set of operations
90+
* @param {Workspace} workspace
91+
* @param {string} folderName
92+
* @returns {void}
93+
*/
94+
function validateComponentPackageJson(workspace, folderName) {
95+
// Only update the homepage if it does not already exist
96+
if (!workspace.manifest.homepage) {
97+
workspace.set(
98+
'homepage',
99+
`https://opensource.adobe.com/spectrum-web-components/components/${folderName}`
100+
);
101+
}
102+
103+
workspace.set('publishConfig.access', 'public');
104+
workspace.set('keywords', keywords(['component', 'css']));
105+
workspace.set('main', './src/index.js');
106+
workspace.set('module', './src/index.js');
107+
workspace.set('type', 'module');
108+
}
109+
110+
/**
111+
* This function rolls up all the package.json requirements
112+
* for all workspaces into a single function to simplify
113+
* the workspace for loop into a readable set of operations
114+
* @param {Workspace} workspace
115+
* @returns {void}
116+
*/
117+
function validatePackageJson(workspace) {
118+
const isRoot = workspace.cwd === '.';
119+
const isComponent = components.includes(workspace.cwd);
120+
121+
/**
122+
* -------------- GLOBAL --------------
123+
* Global configuration for all workspaces
124+
*/
125+
if (
126+
!workspace.manifest.license ||
127+
workspace.manifest.license === ''
128+
) {
129+
workspace.set('license', 'Apache-2.0');
130+
}
131+
132+
workspace.set('author', 'Adobe');
133+
134+
workspace.set('repository.type', 'git');
135+
workspace.set(
136+
'repository.url',
137+
'https://github.com/adobe/spectrum-web-components.git'
138+
);
139+
140+
// We don't need to set the directory for the root workspace
141+
if (!isRoot) {
142+
workspace.set('repository.directory', workspace.cwd);
143+
}
144+
145+
workspace.set(
146+
'bugs.url',
147+
'https://github.com/adobe/spectrum-web-components/issues'
148+
);
149+
150+
/**
151+
* -------------- COMPONENTS --------------
152+
* Process the components workspaces with component-specific configuration
153+
*/
154+
if (isComponent) {
155+
const folderName = workspace.cwd?.split('/')?.[1];
156+
validateComponentPackageJson(workspace, folderName);
157+
validateLocalPackages(workspace);
158+
} else {
159+
/**
160+
* -------------- OTHER --------------
161+
* All other workspaces should have at least the following configuration
162+
*/
163+
if (!workspace.manifest.keywords) {
164+
workspace.set('keywords', keywords());
165+
}
166+
167+
if (!workspace.manifest.homepage) {
168+
workspace.set(
169+
'homepage',
170+
'https://opensource.adobe.com/spectrum-web-components/'
171+
);
172+
}
173+
}
174+
}
175+
176+
/**
177+
* This loop iterates over all the workspaces in the project
178+
* and updates the package.json file with the necessary
179+
*/
180+
for (const workspace of Yarn.workspaces()) {
181+
validatePackageJson(workspace);
182+
}
183+
},
184+
});

yarn.lock

+10
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ __metadata:
244244
"@web/test-runner-playwright": "npm:^0.11.0"
245245
"@web/test-runner-visual-regression": "npm:^0.9.0"
246246
"@webcomponents/webcomponentsjs": "npm:^2.8.0"
247+
"@yarnpkg/types": "npm:^4.0.1"
247248
alex: "npm:^11.0.1"
248249
cem-plugin-module-file-extensions: "npm:^0.0.5"
249250
chromatic: "npm:^11.20.0"
@@ -11982,6 +11983,15 @@ __metadata:
1198211983
languageName: node
1198311984
linkType: hard
1198411985

11986+
"@yarnpkg/types@npm:^4.0.1":
11987+
version: 4.0.1
11988+
resolution: "@yarnpkg/types@npm:4.0.1"
11989+
dependencies:
11990+
tslib: "npm:^2.4.0"
11991+
checksum: 10c0/90226789475680ba599833571dd76c0718dd5b4c5022481263ef309d6a628f6246671cd6ca86e49c966ddefa7aca6ccef82240dc1476d2cea702ea5bee2a6b72
11992+
languageName: node
11993+
linkType: hard
11994+
1198511995
"JSONStream@npm:^1.3.5":
1198611996
version: 1.3.5
1198711997
resolution: "JSONStream@npm:1.3.5"

0 commit comments

Comments
 (0)