Skip to content

Commit 715c289

Browse files
committed
Fixing TypeScript build system and making it output types
We no longer parse ALL .ts files for EACH package we're building with rollup. Also, we ouput the the type files straight from rollup back
1 parent 2363995 commit 715c289

Some content is hidden

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

56 files changed

+669
-51
lines changed

.github/workflows/test.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@ jobs:
3333
- run: yarn check-format
3434

3535
js-dist-current:
36-
# always skip check for now - building is too inefficient and large for CI
37-
if: false
3836
runs-on: ubuntu-latest
3937
steps:
4038
- uses: actions/checkout@master

package.json

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"private": true,
33
"workspaces": [
4-
"src/**/assets"
4+
"src/*/assets"
55
],
66
"scripts": {
77
"build": "yarn rollup -c",
@@ -16,9 +16,9 @@
1616
"@babel/preset-env": "^7.15.8",
1717
"@babel/preset-react": "^7.15.8",
1818
"@babel/preset-typescript": "^7.15.8",
19-
"@rollup/plugin-commonjs": "^22.0.0",
20-
"@rollup/plugin-node-resolve": "^13.0.6",
21-
"@rollup/plugin-typescript": "^8.3.0",
19+
"@rollup/plugin-commonjs": "^23.0.0",
20+
"@rollup/plugin-node-resolve": "^15.0.0",
21+
"@rollup/plugin-typescript": "^10.0.0",
2222
"@symfony/stimulus-testing": "^2.0.1",
2323
"@typescript-eslint/eslint-plugin": "^5.2.0",
2424
"@typescript-eslint/parser": "^5.2.0",
@@ -27,9 +27,8 @@
2727
"eslint-config-prettier": "^8.0.0",
2828
"eslint-plugin-jest": "^25.2.2",
2929
"jest": "^27.3.1",
30-
"pkg-up": "^3.1.0",
3130
"prettier": "^2.2.1",
32-
"rollup": "^2.68.0",
31+
"rollup": "^3.7.0",
3332
"tslib": "^2.3.1",
3433
"typescript": "^4.4.4"
3534
},

rollup.config.js

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import resolve from '@rollup/plugin-node-resolve';
2-
import commonjs from '@rollup/plugin-commonjs';
3-
import typescript from '@rollup/plugin-typescript';
4-
import glob from 'glob';
5-
import path from 'path';
6-
import pkgUp from 'pkg-up';
1+
const resolve = require('@rollup/plugin-node-resolve');
2+
const commonjs = require('@rollup/plugin-commonjs');
3+
const typescript = require('@rollup/plugin-typescript');
4+
const fs = require('fs');
5+
const glob = require('glob');
6+
const path = require('path');
77

88
/**
99
* Guarantees that any files imported from a peer dependency are treated as an external.
@@ -38,10 +38,34 @@ const wildcardExternalsPlugin = (peerDependencies) => ({
3838
}
3939
});
4040

41+
/**
42+
* Moves the generated TypeScript declaration files to the correct location.
43+
*
44+
* This could probably be configured in the TypeScript plugin.
45+
*/
46+
const moveTypescriptDeclarationsPlugin = (packagePath) => ({
47+
name: 'move-ts-declarations',
48+
writeBundle: async () => {
49+
const files = glob.sync(path.join(packagePath, 'dist', '*', 'assets', 'src', '**/*.d.ts'));
50+
files.forEach((file) => {
51+
// a bit odd, but remove first 7 directories, which will leave
52+
// only the relative path to the file
53+
const relativePath = file.split('/').slice(7).join('/');
54+
55+
const targetFile = path.join(packagePath, 'dist', relativePath);
56+
if (!fs.existsSync(path.dirname(targetFile))) {
57+
fs.mkdirSync(path.dirname(targetFile), { recursive: true });
58+
}
59+
fs.renameSync(file, targetFile);
60+
});
61+
}
62+
});
63+
4164
const files = glob.sync('src/*/assets/src/*controller.ts');
42-
const packages = files.map((file) => {
43-
const absolutePath = path.join(__dirname, file);
44-
const packageData = require(pkgUp.sync({ cwd: absolutePath }));
65+
module.exports = files.map((file) => {
66+
const packageRoot = path.join(file, '..', '..');
67+
const packagePath = path.join(packageRoot, 'package.json');
68+
const packageData = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
4569
const peerDependencies = [
4670
'@hotwired/stimulus',
4771
...(packageData.peerDependencies ? Object.keys(packageData.peerDependencies) : [])
@@ -50,21 +74,28 @@ const packages = files.map((file) => {
5074
return {
5175
input: file,
5276
output: {
53-
file: path.join(absolutePath, '..', '..', 'dist', path.basename(file, '.ts') + '.js'),
77+
file: path.join(packageRoot, 'dist', path.basename(file, '.ts') + '.js'),
5478
format: 'esm',
5579
},
5680
external: peerDependencies,
5781
plugins: [
5882
resolve(),
59-
typescript(),
83+
typescript({
84+
filterRoot: packageRoot,
85+
include: ['src/**/*.ts'],
86+
compilerOptions: {
87+
outDir: 'dist',
88+
declaration: true,
89+
emitDeclarationOnly: true,
90+
}
91+
}),
6092
commonjs({
6193
namedExports: {
6294
'react-dom/client': ['createRoot'],
6395
},
6496
}),
65-
wildcardExternalsPlugin(peerDependencies)
97+
wildcardExternalsPlugin(peerDependencies),
98+
moveTypescriptDeclarationsPlugin(packageRoot),
6699
],
67100
};
68101
});
69-
70-
export default packages;
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { Controller } from '@hotwired/stimulus';
2+
import TomSelect from 'tom-select';
3+
export default class extends Controller {
4+
#private;
5+
static values: {
6+
url: StringConstructor;
7+
optionsAsHtml: BooleanConstructor;
8+
noResultsFoundText: StringConstructor;
9+
noMoreResultsText: StringConstructor;
10+
minCharacters: NumberConstructor;
11+
tomSelectOptions: ObjectConstructor;
12+
preload: StringConstructor;
13+
};
14+
readonly urlValue: string;
15+
readonly optionsAsHtmlValue: boolean;
16+
readonly noMoreResultsTextValue: string;
17+
readonly noResultsFoundTextValue: string;
18+
readonly minCharactersValue: number;
19+
readonly tomSelectOptionsValue: object;
20+
readonly hasPreloadValue: boolean;
21+
readonly preloadValue: string;
22+
tomSelect: TomSelect;
23+
initialize(): void;
24+
connect(): void;
25+
disconnect(): void;
26+
get selectElement(): HTMLSelectElement | null;
27+
get formElement(): HTMLInputElement | HTMLSelectElement;
28+
get preload(): string | boolean;
29+
}

src/Autocomplete/assets/dist/controller.js

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ function __classPrivateFieldGet(receiver, state, kind, f) {
2222
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
2323
}
2424

25-
var _instances, _getCommonConfig, _createAutocomplete, _createAutocompleteWithHtmlContents, _createAutocompleteWithRemoteData, _stripTags, _mergeObjects, _createTomSelect, _dispatchEvent;
25+
var _default_1_instances, _default_1_getCommonConfig, _default_1_createAutocomplete, _default_1_createAutocompleteWithHtmlContents, _default_1_createAutocompleteWithRemoteData, _default_1_stripTags, _default_1_mergeObjects, _default_1_createTomSelect, _default_1_dispatchEvent;
2626
class default_1 extends Controller {
2727
constructor() {
2828
super(...arguments);
29-
_instances.add(this);
29+
_default_1_instances.add(this);
3030
}
3131
initialize() {
3232
this.element.setAttribute('data-live-ignore', '');
@@ -39,14 +39,14 @@ class default_1 extends Controller {
3939
}
4040
connect() {
4141
if (this.urlValue) {
42-
this.tomSelect = __classPrivateFieldGet(this, _instances, "m", _createAutocompleteWithRemoteData).call(this, this.urlValue, this.minCharactersValue);
42+
this.tomSelect = __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_createAutocompleteWithRemoteData).call(this, this.urlValue, this.minCharactersValue);
4343
return;
4444
}
4545
if (this.optionsAsHtmlValue) {
46-
this.tomSelect = __classPrivateFieldGet(this, _instances, "m", _createAutocompleteWithHtmlContents).call(this);
46+
this.tomSelect = __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_createAutocompleteWithHtmlContents).call(this);
4747
return;
4848
}
49-
this.tomSelect = __classPrivateFieldGet(this, _instances, "m", _createAutocomplete).call(this);
49+
this.tomSelect = __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_createAutocomplete).call(this);
5050
}
5151
disconnect() {
5252
this.tomSelect.revertSettings.innerHTML = this.element.innerHTML;
@@ -77,7 +77,7 @@ class default_1 extends Controller {
7777
return this.preloadValue;
7878
}
7979
}
80-
_instances = new WeakSet(), _getCommonConfig = function _getCommonConfig() {
80+
_default_1_instances = new WeakSet(), _default_1_getCommonConfig = function _default_1_getCommonConfig() {
8181
const plugins = {};
8282
const isMultiple = !this.selectElement || this.selectElement.multiple;
8383
if (!this.formElement.disabled && !isMultiple) {
@@ -109,19 +109,19 @@ _instances = new WeakSet(), _getCommonConfig = function _getCommonConfig() {
109109
if (!this.selectElement && !this.urlValue) {
110110
config.shouldLoad = () => false;
111111
}
112-
return __classPrivateFieldGet(this, _instances, "m", _mergeObjects).call(this, config, this.tomSelectOptionsValue);
113-
}, _createAutocomplete = function _createAutocomplete() {
114-
const config = __classPrivateFieldGet(this, _instances, "m", _mergeObjects).call(this, __classPrivateFieldGet(this, _instances, "m", _getCommonConfig).call(this), {
112+
return __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_mergeObjects).call(this, config, this.tomSelectOptionsValue);
113+
}, _default_1_createAutocomplete = function _default_1_createAutocomplete() {
114+
const config = __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_mergeObjects).call(this, __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_getCommonConfig).call(this), {
115115
maxOptions: this.selectElement ? this.selectElement.options.length : 50,
116116
});
117-
return __classPrivateFieldGet(this, _instances, "m", _createTomSelect).call(this, config);
118-
}, _createAutocompleteWithHtmlContents = function _createAutocompleteWithHtmlContents() {
119-
const config = __classPrivateFieldGet(this, _instances, "m", _mergeObjects).call(this, __classPrivateFieldGet(this, _instances, "m", _getCommonConfig).call(this), {
117+
return __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_createTomSelect).call(this, config);
118+
}, _default_1_createAutocompleteWithHtmlContents = function _default_1_createAutocompleteWithHtmlContents() {
119+
const config = __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_mergeObjects).call(this, __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_getCommonConfig).call(this), {
120120
maxOptions: this.selectElement ? this.selectElement.options.length : 50,
121121
score: (search) => {
122122
const scoringFunction = this.tomSelect.getScoreFunction(search);
123123
return (item) => {
124-
return scoringFunction(Object.assign(Object.assign({}, item), { text: __classPrivateFieldGet(this, _instances, "m", _stripTags).call(this, item.text) }));
124+
return scoringFunction(Object.assign(Object.assign({}, item), { text: __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_stripTags).call(this, item.text) }));
125125
};
126126
},
127127
render: {
@@ -133,9 +133,9 @@ _instances = new WeakSet(), _getCommonConfig = function _getCommonConfig() {
133133
},
134134
},
135135
});
136-
return __classPrivateFieldGet(this, _instances, "m", _createTomSelect).call(this, config);
137-
}, _createAutocompleteWithRemoteData = function _createAutocompleteWithRemoteData(autocompleteEndpointUrl, minCharacterLength) {
138-
const config = __classPrivateFieldGet(this, _instances, "m", _mergeObjects).call(this, __classPrivateFieldGet(this, _instances, "m", _getCommonConfig).call(this), {
136+
return __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_createTomSelect).call(this, config);
137+
}, _default_1_createAutocompleteWithRemoteData = function _default_1_createAutocompleteWithRemoteData(autocompleteEndpointUrl, minCharacterLength) {
138+
const config = __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_mergeObjects).call(this, __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_getCommonConfig).call(this), {
139139
firstUrl: (query) => {
140140
const separator = autocompleteEndpointUrl.includes('?') ? '&' : '?';
141141
return `${autocompleteEndpointUrl}${separator}query=${encodeURIComponent(query)}`;
@@ -175,17 +175,17 @@ _instances = new WeakSet(), _getCommonConfig = function _getCommonConfig() {
175175
},
176176
preload: this.preload,
177177
});
178-
return __classPrivateFieldGet(this, _instances, "m", _createTomSelect).call(this, config);
179-
}, _stripTags = function _stripTags(string) {
178+
return __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_createTomSelect).call(this, config);
179+
}, _default_1_stripTags = function _default_1_stripTags(string) {
180180
return string.replace(/(<([^>]+)>)/gi, '');
181-
}, _mergeObjects = function _mergeObjects(object1, object2) {
181+
}, _default_1_mergeObjects = function _default_1_mergeObjects(object1, object2) {
182182
return Object.assign(Object.assign({}, object1), object2);
183-
}, _createTomSelect = function _createTomSelect(options) {
184-
__classPrivateFieldGet(this, _instances, "m", _dispatchEvent).call(this, 'autocomplete:pre-connect', { options });
183+
}, _default_1_createTomSelect = function _default_1_createTomSelect(options) {
184+
__classPrivateFieldGet(this, _default_1_instances, "m", _default_1_dispatchEvent).call(this, 'autocomplete:pre-connect', { options });
185185
const tomSelect = new TomSelect(this.formElement, options);
186-
__classPrivateFieldGet(this, _instances, "m", _dispatchEvent).call(this, 'autocomplete:connect', { tomSelect, options });
186+
__classPrivateFieldGet(this, _default_1_instances, "m", _default_1_dispatchEvent).call(this, 'autocomplete:connect', { tomSelect, options });
187187
return tomSelect;
188-
}, _dispatchEvent = function _dispatchEvent(name, payload) {
188+
}, _default_1_dispatchEvent = function _default_1_dispatchEvent(name, payload) {
189189
this.element.dispatchEvent(new CustomEvent(name, { detail: payload, bubbles: true }));
190190
};
191191
default_1.values = {

src/Autocomplete/assets/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "@symfony/ux-autocomplete",
33
"description": "JavaScript-powered autocompletion functionality for forms.",
44
"main": "dist/controller.js",
5-
"module": "dist/controller.js",
5+
"types": "dist/controller.d.ts",
66
"version": "1.0.0",
77
"license": "MIT",
88
"symfony": {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { Controller } from '@hotwired/stimulus';
2+
export default class extends Controller {
3+
readonly viewValue: any;
4+
static values: {
5+
view: ObjectConstructor;
6+
};
7+
connect(): void;
8+
_dispatchEvent(name: string, payload: any): void;
9+
}

src/Chartjs/assets/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
"description": "Chart.js integration for Symfony",
44
"license": "MIT",
55
"version": "1.1.0",
6+
"main": "dist/controller.js",
7+
"types": "dist/controller.d.ts",
68
"symfony": {
79
"controllers": {
810
"chart": {
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { Controller } from '@hotwired/stimulus';
2+
export default class CropperController extends Controller {
3+
readonly publicUrlValue: string;
4+
readonly optionsValue: object;
5+
static values: {
6+
publicUrl: StringConstructor;
7+
options: ObjectConstructor;
8+
};
9+
connect(): void;
10+
_dispatchEvent(name: string, payload: any): void;
11+
}

src/Cropperjs/assets/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
"description": "Cropper.js integration for Symfony",
44
"license": "MIT",
55
"version": "1.1.0",
6+
"main": "dist/controller.js",
7+
"types": "dist/controller.d.ts",
68
"symfony": {
79
"controllers": {
810
"cropper": {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { Controller } from '@hotwired/stimulus';
2+
export default class extends Controller {
3+
readonly inputTarget: HTMLInputElement;
4+
readonly placeholderTarget: HTMLDivElement;
5+
readonly previewTarget: HTMLDivElement;
6+
readonly previewClearButtonTarget: HTMLButtonElement;
7+
readonly previewFilenameTarget: HTMLDivElement;
8+
readonly previewImageTarget: HTMLDivElement;
9+
static targets: string[];
10+
connect(): void;
11+
clear(): void;
12+
onInputChange(event: any): void;
13+
_populateImagePreview(file: Blob): void;
14+
_dispatchEvent(name: string, payload?: any): void;
15+
}

src/Dropzone/assets/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
"description": "File input dropzones for Symfony Forms",
44
"license": "MIT",
55
"version": "1.1.0",
6+
"main": "dist/controller.js",
7+
"types": "dist/controller.d.ts",
68
"symfony": {
79
"controllers": {
810
"dropzone": {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { Controller } from '@hotwired/stimulus';
2+
export default class extends Controller {
3+
readonly srcValue: string;
4+
readonly srcsetValue: any;
5+
readonly hasSrcsetValue: boolean;
6+
static values: {
7+
src: StringConstructor;
8+
srcset: ObjectConstructor;
9+
};
10+
connect(): void;
11+
_calculateSrcsetString(): string;
12+
_dispatchEvent(name: string, payload: any): void;
13+
}

src/LazyImage/assets/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
"description": "Lazy image loader and utilities for Symfony",
44
"license": "MIT",
55
"version": "1.1.0",
6+
"main": "dist/controller.js",
7+
"types": "dist/controller.d.ts",
68
"symfony": {
79
"controllers": {
810
"lazy-image": {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import BackendRequest from './BackendRequest';
2+
export interface BackendInterface {
3+
makeRequest(data: any, actions: BackendAction[], updatedModels: string[], childrenFingerprints: any): BackendRequest;
4+
}
5+
export interface BackendAction {
6+
name: string;
7+
args: Record<string, string>;
8+
}
9+
export default class implements BackendInterface {
10+
private url;
11+
private readonly csrfToken;
12+
constructor(url: string, csrfToken?: string | null);
13+
makeRequest(data: any, actions: BackendAction[], updatedModels: string[], childrenFingerprints: any): BackendRequest;
14+
private willDataFitInUrl;
15+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export default class {
2+
promise: Promise<Response>;
3+
actions: string[];
4+
updatedModels: string[];
5+
isResolved: boolean;
6+
constructor(promise: Promise<Response>, actions: string[], updateModels: string[]);
7+
containsOneOfActions(targetedActions: string[]): boolean;
8+
areAnyModelsUpdated(targetedModels: string[]): boolean;
9+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export default class {
2+
response: Response;
3+
private body;
4+
constructor(response: Response);
5+
getBody(): Promise<string>;
6+
}

0 commit comments

Comments
 (0)