@justeattakeaway/pie-webc 0.0.0-snapshot-release-20240502093622 → 0.0.0-snapshot-release-20240513075515
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -12
- package/package.json +7 -6
- package/src/componentService.js +132 -0
- package/src/index.js +27 -0
- package/test/componentService.spec.js +309 -0
- package/vite.config.js +12 -0
- package/add-components.js +0 -90
package/README.md
CHANGED
|
@@ -8,17 +8,20 @@
|
|
|
8
8
|
</a>
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
|
+
|
|
11
12
|
# Table of Contents
|
|
12
13
|
|
|
13
14
|
1. [Introduction](#pie-webc)
|
|
14
15
|
2. [Installation](#installation)
|
|
15
16
|
3. [Contributing](#contributing)
|
|
16
17
|
|
|
18
|
+
|
|
17
19
|
## pie-webc
|
|
18
20
|
|
|
19
|
-
`pie-webc` is a
|
|
21
|
+
`pie-webc` is a wrapper package which contains **all** PIE web components.
|
|
22
|
+
|
|
23
|
+
This means that after installing this package as a dependency, you can use as many PIE web components as you like, without bloating your application with unused code, or slowing it down with unnecessary component registrations in the browser.
|
|
20
24
|
|
|
21
|
-
This package can be easily integrated into various frontend frameworks and customized through a set of properties.
|
|
22
25
|
|
|
23
26
|
## Installation
|
|
24
27
|
|
|
@@ -32,35 +35,43 @@ $ npm i @justeattakeaway/pie-webc
|
|
|
32
35
|
$ yarn add @justeattakeaway/pie-webc
|
|
33
36
|
```
|
|
34
37
|
|
|
38
|
+
|
|
35
39
|
## Importing components
|
|
36
40
|
|
|
37
|
-
Simply import each
|
|
41
|
+
Simply import each component individually using its specific entrypoint.
|
|
38
42
|
|
|
39
43
|
```js
|
|
40
44
|
import '@justeattakeaway/pie-webc/components/button.js';
|
|
41
45
|
import '@justeattakeaway/pie-webc/components/modal.js';
|
|
42
46
|
```
|
|
43
47
|
|
|
44
|
-
|
|
48
|
+
Or for React applications:
|
|
45
49
|
|
|
46
|
-
```
|
|
50
|
+
```js
|
|
47
51
|
import { PieButton } from '@justeattakeaway/pie-webc/react/button.js';
|
|
48
52
|
import { PieModal } from '@justeattakeaway/pie-webc/react/modal.js';
|
|
49
53
|
```
|
|
50
54
|
|
|
51
|
-
|
|
52
55
|
For full information on using PIE components as part of an application, check out the [Getting Started Guide](https://github.com/justeattakeaway/pie/wiki/Getting-started-with-PIE-Web-Components).
|
|
53
56
|
|
|
54
|
-
## Contributing
|
|
55
57
|
|
|
56
|
-
|
|
58
|
+
## For maintainers
|
|
57
59
|
|
|
58
|
-
|
|
59
|
-
There is a command that can be run to add all pie components to this package. The command is:
|
|
60
|
+
There is a command that can be run (from the root of the monorepo) which adds all PIE components to this package:
|
|
60
61
|
|
|
61
62
|
```npx add-components```
|
|
62
63
|
|
|
63
|
-
|
|
64
|
+
This does the following:
|
|
65
|
+
1. Loops through the (root) `packages/components` folder to find all of the PIE components, ignoring non-component folders, helper packages, and this package itself.
|
|
66
|
+
2. Adds a `.js` and `.d.ts` file for each component to both the `components` and `react` directories (inside `pie-webc`).
|
|
67
|
+
3. Adds entries for each component to the `exports` field in `pie-webc/package.json`.
|
|
68
|
+
4. Adds entries for each component to the `dependencies` field in `pie-webc/package.json`, using the current (latest) version.
|
|
69
|
+
|
|
70
|
+
**Generally, there should be no need to run this script.** The only time it should be run is when a new component is created using the [component generator](../../tools/generator-pie-component/README.md). The generator runs this script automatically after creating a new component.
|
|
71
|
+
|
|
72
|
+
`changeset` should also make sure that the versions of components are up-to-date.
|
|
64
73
|
|
|
65
|
-
Generally, there should be no need to run this script. The only time it should be run is when we generated a new component using the component generator. The generator will take care of running this script automatically, so it should be a rare occurrence that it needs to be run manually.
|
|
66
74
|
|
|
75
|
+
## Contributing
|
|
76
|
+
|
|
77
|
+
Check out our [contributing guide](https://github.com/justeattakeaway/pie/wiki/Contributing-Guide) for more information on [local development](https://github.com/justeattakeaway/pie/wiki/Contributing-Guide#local-development).
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@justeattakeaway/pie-webc",
|
|
3
3
|
"description": "Component bundle containing all PIE web components",
|
|
4
|
-
"version": "0.0.0-snapshot-release-
|
|
4
|
+
"version": "0.0.0-snapshot-release-20240513075515",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
7
7
|
"**/*.js",
|
|
@@ -170,20 +170,21 @@
|
|
|
170
170
|
}
|
|
171
171
|
},
|
|
172
172
|
"bin": {
|
|
173
|
-
"add-components": "./
|
|
173
|
+
"add-components": "./src/index.js"
|
|
174
174
|
},
|
|
175
175
|
"scripts": {
|
|
176
176
|
"lint:scripts": "run -T eslint .",
|
|
177
177
|
"lint:scripts:fix": "yarn lint:scripts --fix",
|
|
178
178
|
"lint:style": "echo \"Error: no scss / css to lint\" && exit 0",
|
|
179
179
|
"lint:style:fix": "yarn lint:style --fix",
|
|
180
|
-
"test": "
|
|
180
|
+
"test": "run -T vitest run --config ./vite.config.js",
|
|
181
181
|
"test:ci": "yarn test"
|
|
182
182
|
},
|
|
183
183
|
"author": "Just Eat Takeaway.com - Design System Team",
|
|
184
184
|
"license": "Apache-2.0",
|
|
185
185
|
"devDependencies": {
|
|
186
|
-
"@justeattakeaway/pie-components-config": "0.16.0"
|
|
186
|
+
"@justeattakeaway/pie-components-config": "0.16.0",
|
|
187
|
+
"chalk": "5.3.0"
|
|
187
188
|
},
|
|
188
189
|
"dependencies": {
|
|
189
190
|
"@justeattakeaway/pie-assistive-text": "0.3.6",
|
|
@@ -195,10 +196,10 @@
|
|
|
195
196
|
"@justeattakeaway/pie-divider": "0.13.4",
|
|
196
197
|
"@justeattakeaway/pie-form-label": "0.13.4",
|
|
197
198
|
"@justeattakeaway/pie-icon-button": "0.28.5",
|
|
198
|
-
"@justeattakeaway/pie-input": "0.
|
|
199
|
+
"@justeattakeaway/pie-input": "0.19.0",
|
|
199
200
|
"@justeattakeaway/pie-link": "0.17.4",
|
|
200
201
|
"@justeattakeaway/pie-modal": "0.42.5",
|
|
201
|
-
"@justeattakeaway/pie-notification": "0.
|
|
202
|
+
"@justeattakeaway/pie-notification": "0.6.0",
|
|
202
203
|
"@justeattakeaway/pie-spinner": "0.6.4",
|
|
203
204
|
"@justeattakeaway/pie-switch": "0.29.4",
|
|
204
205
|
"@justeattakeaway/pie-tag": "0.9.5"
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
|
|
3
|
+
export class ComponentService {
|
|
4
|
+
constructor (fs, path) {
|
|
5
|
+
this.fs = fs;
|
|
6
|
+
this.path = path;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
getPathShortcuts (workingDir) {
|
|
10
|
+
const componentsSourceDir = this.path.resolve(workingDir, 'packages/components');
|
|
11
|
+
const pieWebcDir = this.path.join(componentsSourceDir, 'pie-webc');
|
|
12
|
+
const componentsTargetDir = this.path.join(pieWebcDir, 'components');
|
|
13
|
+
const reactTargetDir = this.path.join(pieWebcDir, 'react');
|
|
14
|
+
const pieWebcPackageJsonPath = this.path.join(pieWebcDir, 'package.json');
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
componentsSourceDir,
|
|
18
|
+
componentsTargetDir,
|
|
19
|
+
reactTargetDir,
|
|
20
|
+
pieWebcPackageJsonPath,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
ensureDirectoryExists (dir) {
|
|
25
|
+
if (!this.fs.existsSync(dir)) {
|
|
26
|
+
this.fs.mkdirSync(dir, { recursive: true });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
readAndPreparePackageJson (packageJsonPath) {
|
|
31
|
+
const packageJsonData = this.fs.readFileSync(packageJsonPath, 'utf-8');
|
|
32
|
+
const packageJson = JSON.parse(packageJsonData);
|
|
33
|
+
packageJson.exports = packageJson.exports || {};
|
|
34
|
+
packageJson.dependencies = packageJson.dependencies || {};
|
|
35
|
+
|
|
36
|
+
return packageJson;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
verifyRootDirectory (workingDir, expectedPackageName) {
|
|
40
|
+
const packageJsonPath = this.path.join(workingDir, 'package.json');
|
|
41
|
+
|
|
42
|
+
if (!this.fs.existsSync(packageJsonPath)) {
|
|
43
|
+
throw new Error(chalk.redBright('Please run this script from the root of the monorepo.'));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const packageJson = JSON.parse(this.fs.readFileSync(packageJsonPath, 'utf8'));
|
|
47
|
+
|
|
48
|
+
if (packageJson.name !== expectedPackageName) {
|
|
49
|
+
throw new Error(chalk.redBright('Incorrect package: Please run this script from the root of the monorepo.'));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
createPackageJsonExports (componentName) {
|
|
54
|
+
const exports = {
|
|
55
|
+
[`./components/${componentName}.js`]: {
|
|
56
|
+
import: `./components/${componentName}.js`,
|
|
57
|
+
require: `./components/${componentName}.js`,
|
|
58
|
+
types: `./components/${componentName}.d.ts`,
|
|
59
|
+
},
|
|
60
|
+
[`./react/${componentName}.js`]: {
|
|
61
|
+
import: `./react/${componentName}.js`,
|
|
62
|
+
require: `./react/${componentName}.js`,
|
|
63
|
+
types: `./react/${componentName}.d.ts`,
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
return exports;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
writeFilesForComponent (componentName, target) {
|
|
71
|
+
const jsFilePath = this.path.join(target.dir, `${componentName}.js`);
|
|
72
|
+
const tsFilePath = this.path.join(target.dir, `${componentName}.d.ts`);
|
|
73
|
+
|
|
74
|
+
const fileContent = `export * from '${target.exportPath}';\n`;
|
|
75
|
+
this.fs.writeFileSync(jsFilePath, fileContent);
|
|
76
|
+
this.fs.writeFileSync(tsFilePath, fileContent);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
writePackageJson (path, content) {
|
|
80
|
+
this.fs.writeFileSync(path, `${JSON.stringify(content, null, 2)}\n`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
processComponents (workingDir, excludedFolders, packageJson) {
|
|
84
|
+
const newPackageJson = { ...packageJson };
|
|
85
|
+
const {
|
|
86
|
+
componentsSourceDir, componentsTargetDir, reactTargetDir,
|
|
87
|
+
} = this.getPathShortcuts(workingDir);
|
|
88
|
+
|
|
89
|
+
this.fs.readdirSync(componentsSourceDir).forEach((folder) => {
|
|
90
|
+
if (!folder.startsWith('pie-')) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (excludedFolders.includes(folder)) {
|
|
94
|
+
console.info(chalk.yellow(`Excluding: ${chalk.white(folder)}`));
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const fullFolderPath = this.path.join(componentsSourceDir, folder);
|
|
99
|
+
const componentName = folder.replace('pie-', '');
|
|
100
|
+
const packageName = `@justeattakeaway/${folder}`;
|
|
101
|
+
const componentPackageJsonPath = this.path.join(fullFolderPath, 'package.json');
|
|
102
|
+
const componentPackageJsonData = this.fs.readFileSync(componentPackageJsonPath, 'utf-8');
|
|
103
|
+
const componentPackageJson = JSON.parse(componentPackageJsonData);
|
|
104
|
+
|
|
105
|
+
newPackageJson.dependencies[packageName] = componentPackageJson.version;
|
|
106
|
+
|
|
107
|
+
const targets = [
|
|
108
|
+
{
|
|
109
|
+
dir: componentsTargetDir,
|
|
110
|
+
exportPath: packageName,
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
dir: reactTargetDir,
|
|
114
|
+
exportPath: `${packageName}/dist/react.js`,
|
|
115
|
+
}
|
|
116
|
+
];
|
|
117
|
+
|
|
118
|
+
console.info(chalk.gray(`Adding: ${chalk.white(folder)}`));
|
|
119
|
+
|
|
120
|
+
targets.forEach((target) => {
|
|
121
|
+
this.writeFilesForComponent(componentName, target);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
newPackageJson.exports = {
|
|
125
|
+
...newPackageJson.exports,
|
|
126
|
+
...this.createPackageJsonExports(componentName),
|
|
127
|
+
};
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
return newPackageJson;
|
|
131
|
+
}
|
|
132
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
|
|
6
|
+
import { ComponentService } from './componentService.js';
|
|
7
|
+
|
|
8
|
+
const main = (fs, path) => {
|
|
9
|
+
const workingDir = process.cwd();
|
|
10
|
+
const componentService = new ComponentService(fs, path);
|
|
11
|
+
componentService.verifyRootDirectory(workingDir, 'pie-monorepo');
|
|
12
|
+
|
|
13
|
+
const { componentsTargetDir, reactTargetDir, pieWebcPackageJsonPath } = componentService.getPathShortcuts(workingDir);
|
|
14
|
+
|
|
15
|
+
componentService.ensureDirectoryExists(componentsTargetDir);
|
|
16
|
+
componentService.ensureDirectoryExists(reactTargetDir);
|
|
17
|
+
|
|
18
|
+
const pieWebcPackageJson = componentService.readAndPreparePackageJson(pieWebcPackageJsonPath);
|
|
19
|
+
|
|
20
|
+
const excludedFolders = ['pie-webc', 'pie-webc-core', 'pie-webc-testing'];
|
|
21
|
+
const updatedPackageJson = componentService.processComponents(workingDir, excludedFolders, pieWebcPackageJson);
|
|
22
|
+
|
|
23
|
+
componentService.writePackageJson(pieWebcPackageJsonPath, updatedPackageJson);
|
|
24
|
+
console.info(chalk.green('\nAll components added to pie-webc!'));
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
main(fs, path);
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import { ComponentService } from '../src/componentService';
|
|
2
|
+
|
|
3
|
+
describe('ComponentService', () => {
|
|
4
|
+
let fsMock;
|
|
5
|
+
let pathMock;
|
|
6
|
+
let componentService;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
fsMock = {
|
|
10
|
+
existsSync: vi.fn(),
|
|
11
|
+
mkdirSync: vi.fn(),
|
|
12
|
+
readdirSync: vi.fn(),
|
|
13
|
+
readFileSync: vi.fn(),
|
|
14
|
+
writeFileSync: vi.fn(),
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
pathMock = {
|
|
18
|
+
join: vi.fn(),
|
|
19
|
+
resolve: vi.fn(),
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
pathMock.join.mockImplementation((...args) => args.join('/'));
|
|
23
|
+
pathMock.resolve.mockImplementation((...args) => args.join('/'));
|
|
24
|
+
|
|
25
|
+
// Suppress console output
|
|
26
|
+
vi.spyOn(console, 'info').mockImplementation(() => {}); // eslint-disable-line @typescript-eslint/no-empty-function
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe('ensureDirectoryExists', () => {
|
|
30
|
+
it('should create a directory if it does not exist', () => {
|
|
31
|
+
// Arrange
|
|
32
|
+
fsMock.existsSync.mockReturnValue(false);
|
|
33
|
+
componentService = new ComponentService(fsMock, pathMock);
|
|
34
|
+
|
|
35
|
+
// Act
|
|
36
|
+
componentService.ensureDirectoryExists('dir');
|
|
37
|
+
|
|
38
|
+
// Assert
|
|
39
|
+
expect(fsMock.mkdirSync).toHaveBeenCalledWith('dir', { recursive: true });
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should not create a directory if it already exists', () => {
|
|
43
|
+
// Arrange
|
|
44
|
+
fsMock.existsSync.mockReturnValue(true);
|
|
45
|
+
componentService = new ComponentService(fsMock, pathMock);
|
|
46
|
+
|
|
47
|
+
// Act
|
|
48
|
+
componentService.ensureDirectoryExists('dir');
|
|
49
|
+
|
|
50
|
+
// Assert
|
|
51
|
+
expect(fsMock.mkdirSync).not.toHaveBeenCalled();
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('readAndPreparePackageJson', () => {
|
|
56
|
+
it('should return the packageJson with empty exports and dependencies objects if they do not exist', () => {
|
|
57
|
+
// Arrange
|
|
58
|
+
fsMock.readFileSync.mockReturnValue('{}');
|
|
59
|
+
componentService = new ComponentService(fsMock, pathMock);
|
|
60
|
+
|
|
61
|
+
// Act
|
|
62
|
+
const result = componentService.readAndPreparePackageJson('packageJsonPath');
|
|
63
|
+
|
|
64
|
+
// Assert
|
|
65
|
+
expect(result.exports).toEqual({});
|
|
66
|
+
expect(result.dependencies).toEqual({});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should return the packageJson with existing exports and dependencies objects if they exist', () => {
|
|
70
|
+
// Arrange
|
|
71
|
+
fsMock.readFileSync.mockReturnValue('{"exports": {"exportKey": "exportValue"}, "dependencies": {"depKey": "depValue"}}');
|
|
72
|
+
componentService = new ComponentService(fsMock, pathMock);
|
|
73
|
+
|
|
74
|
+
// Act
|
|
75
|
+
const result = componentService.readAndPreparePackageJson('/path/to/package.json');
|
|
76
|
+
|
|
77
|
+
// Assert
|
|
78
|
+
expect(result.exports).toEqual({ exportKey: 'exportValue' });
|
|
79
|
+
expect(result.dependencies).toEqual({ depKey: 'depValue' });
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe('verifyRootDirectory', () => {
|
|
84
|
+
beforeEach(() => {
|
|
85
|
+
pathMock.join.mockReturnValue('');
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should throw an error if there is no package.json file in the working directory', () => {
|
|
89
|
+
// Arrange
|
|
90
|
+
fsMock.existsSync.mockReturnValue(false);
|
|
91
|
+
componentService = new ComponentService(fsMock, pathMock);
|
|
92
|
+
|
|
93
|
+
// Act & Assert
|
|
94
|
+
const testFn = () => componentService.verifyRootDirectory('workingDir', 'expectedPackageName');
|
|
95
|
+
expect(testFn).toThrowError('Please run this script from the root of the monorepo.');
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should throw an error if the package.json does not match the expected name', () => {
|
|
99
|
+
// Arrange
|
|
100
|
+
fsMock.existsSync.mockReturnValue(true);
|
|
101
|
+
fsMock.readFileSync.mockReturnValue('{"name": "wrongPackageName"}');
|
|
102
|
+
componentService = new ComponentService(fsMock, pathMock);
|
|
103
|
+
|
|
104
|
+
// Act & Assert
|
|
105
|
+
const testFn = () => componentService.verifyRootDirectory('workingDir', 'expectedPackageName');
|
|
106
|
+
expect(testFn).toThrowError('Incorrect package: Please run this script from the root of the monorepo.');
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('should not throw any errors if the package.json name matches the expected name', () => {
|
|
110
|
+
// Arrange
|
|
111
|
+
fsMock.existsSync.mockReturnValue(true);
|
|
112
|
+
fsMock.readFileSync.mockReturnValue('{"name": "expectedPackageName"}');
|
|
113
|
+
componentService = new ComponentService(fsMock, pathMock);
|
|
114
|
+
|
|
115
|
+
// Act & Assert
|
|
116
|
+
const testFn = () => componentService.verifyRootDirectory('workingDir', 'expectedPackageName');
|
|
117
|
+
expect(testFn).not.toThrow();
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
describe('createPackageJsonExports', () => {
|
|
122
|
+
it('should return an object with exports for the component', () => {
|
|
123
|
+
// Arrange
|
|
124
|
+
componentService = new ComponentService(fsMock, pathMock);
|
|
125
|
+
|
|
126
|
+
// Act
|
|
127
|
+
const result = componentService.createPackageJsonExports('component-name');
|
|
128
|
+
|
|
129
|
+
// Assert
|
|
130
|
+
expect(result).toEqual({
|
|
131
|
+
'./components/component-name.js': {
|
|
132
|
+
import: './components/component-name.js',
|
|
133
|
+
require: './components/component-name.js',
|
|
134
|
+
types: './components/component-name.d.ts',
|
|
135
|
+
},
|
|
136
|
+
'./react/component-name.js': {
|
|
137
|
+
import: './react/component-name.js',
|
|
138
|
+
require: './react/component-name.js',
|
|
139
|
+
types: './react/component-name.d.ts',
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
describe('writeFilesForComponent', () => {
|
|
146
|
+
it('should write the component files to the target directory', () => {
|
|
147
|
+
// Arrange
|
|
148
|
+
componentService = new ComponentService(fsMock, pathMock);
|
|
149
|
+
const target = {
|
|
150
|
+
dir: 'componentsTargetDir',
|
|
151
|
+
exportPath: 'packageName',
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// Act
|
|
155
|
+
componentService.writeFilesForComponent('component-name', target);
|
|
156
|
+
|
|
157
|
+
// Assert
|
|
158
|
+
expect(fsMock.writeFileSync).toHaveBeenCalledWith('componentsTargetDir/component-name.js', "export * from 'packageName';\n");
|
|
159
|
+
expect(fsMock.writeFileSync).toHaveBeenCalledWith('componentsTargetDir/component-name.d.ts', "export * from 'packageName';\n");
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
describe('writePackageJson', () => {
|
|
164
|
+
it('should write the stringified content to the specified path', () => {
|
|
165
|
+
// Arrange
|
|
166
|
+
componentService = new ComponentService(fsMock, pathMock);
|
|
167
|
+
const packageJson = { name: 'package-name', version: '1.0.0' };
|
|
168
|
+
|
|
169
|
+
// Act
|
|
170
|
+
componentService.writePackageJson('path/to/package.json', packageJson);
|
|
171
|
+
|
|
172
|
+
// Assert
|
|
173
|
+
expect(fsMock.writeFileSync).toHaveBeenCalledWith('path/to/package.json', '{\n "name": "package-name",\n "version": "1.0.0"\n}\n');
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
describe('processComponents', () => {
|
|
178
|
+
let excludedFolders;
|
|
179
|
+
let workingDir;
|
|
180
|
+
|
|
181
|
+
beforeEach(() => {
|
|
182
|
+
excludedFolders = [];
|
|
183
|
+
workingDir = 'workingDir';
|
|
184
|
+
|
|
185
|
+
fsMock.readFileSync.mockReturnValue('{"version": "1.1.1"}'); // Component package.json
|
|
186
|
+
fsMock.readdirSync.mockReturnValue(['pie-component-name']); // Default, overridden by some tests
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('should ignore non-component folders', () => {
|
|
190
|
+
// Arrange
|
|
191
|
+
fsMock.readdirSync.mockReturnValue(['not-a-component']);
|
|
192
|
+
componentService = new ComponentService(fsMock, pathMock);
|
|
193
|
+
|
|
194
|
+
// Act
|
|
195
|
+
componentService.processComponents(workingDir, excludedFolders, {});
|
|
196
|
+
|
|
197
|
+
// Assert
|
|
198
|
+
expect(fsMock.writeFileSync).not.toHaveBeenCalled();
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('should ignore excluded folders', () => {
|
|
202
|
+
// Arrange
|
|
203
|
+
fsMock.readdirSync.mockReturnValue(['pie-excluded']);
|
|
204
|
+
componentService = new ComponentService(fsMock, pathMock);
|
|
205
|
+
|
|
206
|
+
excludedFolders = ['pie-excluded'];
|
|
207
|
+
|
|
208
|
+
// Act
|
|
209
|
+
componentService.processComponents(workingDir, excludedFolders, {});
|
|
210
|
+
|
|
211
|
+
// Assert
|
|
212
|
+
expect(fsMock.writeFileSync).not.toHaveBeenCalled();
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('should add components as dependencies to the package.json', () => {
|
|
216
|
+
// Arrange
|
|
217
|
+
componentService = new ComponentService(fsMock, pathMock);
|
|
218
|
+
const spy = vi.spyOn(componentService, 'writeFilesForComponent');
|
|
219
|
+
|
|
220
|
+
// Act
|
|
221
|
+
componentService.processComponents(workingDir, excludedFolders, { dependencies: {} });
|
|
222
|
+
|
|
223
|
+
// Assert
|
|
224
|
+
expect(spy).toHaveBeenCalledWith('component-name', {
|
|
225
|
+
dir: 'workingDir/packages/components/pie-webc/components',
|
|
226
|
+
exportPath: '@justeattakeaway/pie-component-name',
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
expect(spy).toHaveBeenCalledWith('component-name', {
|
|
230
|
+
dir: 'workingDir/packages/components/pie-webc/react',
|
|
231
|
+
exportPath: '@justeattakeaway/pie-component-name/dist/react.js',
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it('should add exports for each component to the package.json', () => {
|
|
236
|
+
// Arrange
|
|
237
|
+
componentService = new ComponentService(fsMock, pathMock);
|
|
238
|
+
const rootPackageJson = { dependencies: {} };
|
|
239
|
+
|
|
240
|
+
// Act
|
|
241
|
+
const { exports } = componentService.processComponents(workingDir, excludedFolders, rootPackageJson);
|
|
242
|
+
|
|
243
|
+
// Assert
|
|
244
|
+
expect(Object.keys(exports)).toHaveLength(2);
|
|
245
|
+
expect(Object.keys(exports)).toContain('./components/component-name.js');
|
|
246
|
+
expect(Object.keys(exports)).toContain('./react/component-name.js');
|
|
247
|
+
// Content of the exports object is tested in createPackageJsonExports
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it('should preserve existing exports in the package.json', () => {
|
|
251
|
+
// Arrange
|
|
252
|
+
componentService = new ComponentService(fsMock, pathMock);
|
|
253
|
+
const rootPackageJson = {
|
|
254
|
+
dependencies: {},
|
|
255
|
+
exports: {
|
|
256
|
+
'./components/existing-component.js': {},
|
|
257
|
+
'./react/existing-component.js': {},
|
|
258
|
+
},
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
// Act
|
|
262
|
+
const { exports } = componentService.processComponents(workingDir, excludedFolders, rootPackageJson);
|
|
263
|
+
|
|
264
|
+
// Assert
|
|
265
|
+
expect(Object.keys(exports)).toContain('./components/existing-component.js');
|
|
266
|
+
expect(Object.keys(exports)).toContain('./react/existing-component.js');
|
|
267
|
+
expect(Object.keys(exports)).toHaveLength(4);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('should override existing exports in the package.json', () => {
|
|
271
|
+
// Arrange
|
|
272
|
+
componentService = new ComponentService(fsMock, pathMock);
|
|
273
|
+
const rootPackageJson = {
|
|
274
|
+
dependencies: {},
|
|
275
|
+
exports: {
|
|
276
|
+
'./components/component-name.js': {},
|
|
277
|
+
'./react/component-name.js': {},
|
|
278
|
+
},
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
// Act
|
|
282
|
+
const { exports } = componentService.processComponents(workingDir, excludedFolders, rootPackageJson);
|
|
283
|
+
|
|
284
|
+
// Assert
|
|
285
|
+
expect(Object.keys(exports)).toContain('./components/component-name.js');
|
|
286
|
+
expect(Object.keys(exports)).toContain('./react/component-name.js');
|
|
287
|
+
expect(Object.keys(exports)).toHaveLength(2);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it('should preserve existing dependencies in the package.json', () => {
|
|
291
|
+
// Arrange
|
|
292
|
+
fsMock.readdirSync.mockReturnValue(['pie-new-component']);
|
|
293
|
+
|
|
294
|
+
componentService = new ComponentService(fsMock, pathMock);
|
|
295
|
+
const rootPackageJson = {
|
|
296
|
+
dependencies: { '@justeattakeaway/pie-existing-component': '1.0.0' },
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
// Act
|
|
300
|
+
const { dependencies } = componentService.processComponents(workingDir, excludedFolders, rootPackageJson);
|
|
301
|
+
|
|
302
|
+
// Assert
|
|
303
|
+
expect(dependencies).toEqual({
|
|
304
|
+
'@justeattakeaway/pie-existing-component': '1.0.0',
|
|
305
|
+
'@justeattakeaway/pie-new-component': '1.1.1',
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
});
|
package/vite.config.js
ADDED
package/add-components.js
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import fs from 'fs';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
|
|
5
|
-
const workingDir = process.cwd();
|
|
6
|
-
|
|
7
|
-
// Function to check if the script is run from the expected directory
|
|
8
|
-
function verifyRootDirectory (expectedPackageName) {
|
|
9
|
-
const packageJsonPath = path.join(workingDir, 'package.json');
|
|
10
|
-
if (!fs.existsSync(packageJsonPath)) {
|
|
11
|
-
console.error('Error: Please run this script from the root of the monorepo.');
|
|
12
|
-
process.exit(1);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
16
|
-
if (packageJson.name !== expectedPackageName) {
|
|
17
|
-
console.error('Error: Please run this script from the root of the monorepo.');
|
|
18
|
-
process.exit(1);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Ensure the script is run from the root of the monorepo
|
|
23
|
-
verifyRootDirectory('pie-monorepo');
|
|
24
|
-
|
|
25
|
-
const componentsSourceDir = path.resolve('packages/components');
|
|
26
|
-
const pieWebcDir = path.join(componentsSourceDir, 'pie-webc');
|
|
27
|
-
const componentsTargetDir = path.join(pieWebcDir, 'components');
|
|
28
|
-
const reactTargetDir = path.join(pieWebcDir, 'react');
|
|
29
|
-
const pieWebcPackageJsonPath = path.join(pieWebcDir, 'package.json');
|
|
30
|
-
const excludedFolders = ['pie-webc', 'pie-webc-core', 'pie-webc-testing'];
|
|
31
|
-
|
|
32
|
-
// Read and parse the package.json of pie-webc
|
|
33
|
-
const pieWebcPackageJsonData = fs.readFileSync(pieWebcPackageJsonPath, 'utf-8');
|
|
34
|
-
const pieWebcPackageJson = JSON.parse(pieWebcPackageJsonData);
|
|
35
|
-
pieWebcPackageJson.exports = pieWebcPackageJson.exports || {};
|
|
36
|
-
pieWebcPackageJson.dependencies = pieWebcPackageJson.dependencies || {};
|
|
37
|
-
|
|
38
|
-
// Ensure target 'components' and 'react' directories exist
|
|
39
|
-
if (!fs.existsSync(componentsTargetDir)) {
|
|
40
|
-
fs.mkdirSync(componentsTargetDir, { recursive: true });
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (!fs.existsSync(reactTargetDir)) {
|
|
44
|
-
fs.mkdirSync(reactTargetDir, { recursive: true });
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Loop over all pie component packages and add them to pie-webc
|
|
48
|
-
fs.readdirSync(componentsSourceDir).forEach((folder) => {
|
|
49
|
-
if (folder.startsWith('pie-') && !excludedFolders.includes(folder)) {
|
|
50
|
-
const fullFolderPath = path.join(componentsSourceDir, folder);
|
|
51
|
-
const componentName = folder.replace('pie-', '');
|
|
52
|
-
const packageName = `@justeattakeaway/${folder}`;
|
|
53
|
-
const componentPackageJsonPath = path.join(fullFolderPath, 'package.json');
|
|
54
|
-
const componentPackageJsonData = fs.readFileSync(componentPackageJsonPath, 'utf-8');
|
|
55
|
-
const componentPackageJson = JSON.parse(componentPackageJsonData);
|
|
56
|
-
|
|
57
|
-
// Add the component package as a dependency to pie-webc
|
|
58
|
-
pieWebcPackageJson.dependencies[packageName] = componentPackageJson.version;
|
|
59
|
-
|
|
60
|
-
const targets = [
|
|
61
|
-
{ dir: componentsTargetDir, type: 'components', exportPath: packageName },
|
|
62
|
-
{ dir: reactTargetDir, type: 'react', exportPath: `${packageName}/dist/react.js` }
|
|
63
|
-
];
|
|
64
|
-
|
|
65
|
-
// Create the js and d.ts files for the component in the target directories
|
|
66
|
-
targets.forEach((target) => {
|
|
67
|
-
const jsFilePath = path.join(target.dir, `${componentName}.js`);
|
|
68
|
-
const tsFilePath = path.join(target.dir, `${componentName}.d.ts`);
|
|
69
|
-
|
|
70
|
-
const fileContent = `export * from '${target.exportPath}';\n`;
|
|
71
|
-
fs.writeFileSync(jsFilePath, fileContent);
|
|
72
|
-
fs.writeFileSync(tsFilePath, fileContent);
|
|
73
|
-
|
|
74
|
-
if (!pieWebcPackageJson.exports) {
|
|
75
|
-
pieWebcPackageJson.exports = {};
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Update exports in the pie-webc package.json to include the component
|
|
79
|
-
pieWebcPackageJson.exports[`./${target.type}/${componentName}.js`] = {
|
|
80
|
-
import: `./${target.type}/${componentName}.js`,
|
|
81
|
-
require: `./${target.type}/${componentName}.js`,
|
|
82
|
-
types: `./${target.type}/${componentName}.d.ts`,
|
|
83
|
-
};
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
// Write updates back to the package.json
|
|
89
|
-
fs.writeFileSync(pieWebcPackageJsonPath, `${JSON.stringify(pieWebcPackageJson, null, 2)}\n`);
|
|
90
|
-
console.info('All components added to pie-webc');
|