Skip to content

Commit ba4dd1b

Browse files
committed
minor #156 Using Typescript & Centralizing Builds (weaverryan)
This PR was squashed before being merged into the main branch. Discussion ---------- Using Typescript & Centralizing Builds | Q | A | ------------- | --- | Bug fix? | No | New feature? | Yes | Tickets | None | License | MIT **Depends on #141** Hi! This PR converts the project to use TypeScript, but that in itself wasn't really the motivation. ## Motivations / Changes * A) Standardize how we do things to be more like ``@hotwired`/stimulus` and other high-quality Stimulus libraries (like `stimulus-use` * B) Centralize the build processes: the "build", "test" and "lint" processes are now all centralized so that each "library" can focus on just doing its job. * C) This **removes support for IE11** (see below). B) Was the main motivator - before, each library was responsible for setting up their own test process and (more importantly) their own build process, which allowed for inconsistencies for what transformations we make, etc. ## IE 11 Support Gone Stimulus 3 dropped IE 11 support. This PR would be released with the version of Symfony UX that starts using Stimulus 3. So, we follow suit. It makes the builds smaller and makes (along with Typescript) our build process MUCH simpler. It's pretty easy to see the difference in the built files - for example https://github.com/symfony/ux/pull/156/files#diff-72060cc03a17f489a2c7e84dd42fab25c7d19ee5154f0c493f00b91d6a13285b ## TODOS * [ ] Some additional cleanup so that the TypeScript build process finishes without warnings (it already finishes without errors). Commits ------- f8eb843 Using Typescript & Centralizing Builds
2 parents 94e8bdf + f8eb843 commit ba4dd1b

File tree

81 files changed

+2067
-3238
lines changed

Some content is hidden

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

81 files changed

+2067
-3238
lines changed

babel.config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
presets: [
3+
['@babel/preset-env', {targets: {node: 'current'}}],
4+
'@babel/preset-typescript',
5+
],
6+
};

jest.config.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const path = require('path');
2+
3+
module.exports = {
4+
testRegex: "test/.*\\.test.ts",
5+
testEnvironment: 'jsdom',
6+
setupFilesAfterEnv: [
7+
path.join(__dirname, 'test/setup.js'),
8+
],
9+
transform: {
10+
'\\.(j|t)s$': ['babel-jest', { configFile: path.join(__dirname, './babel.config.js') }]
11+
},
12+
}

package.json

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,34 +5,56 @@
55
"src/**/assets"
66
],
77
"scripts": {
8-
"build": "yarn workspaces run build",
9-
"test": "yarn workspaces run test",
10-
"lint": "yarn workspaces run lint --fix",
11-
"format": "prettier src/*/Resources/assets/{src,test}/*.js {,src/*/}*.{json,md} --write",
8+
"build": "yarn rollup -c",
9+
"test": "yarn workspaces run jest",
10+
"lint": "yarn workspaces run eslint src test",
11+
"format": "prettier src/*/Resources/assets/src/*.ts src/*/Resources/assets/test/*.js {,src/*/}*.{json,md} --write",
1212
"check-lint": "yarn lint --no-fix",
1313
"check-format": "yarn format --no-write --check"
1414
},
1515
"devDependencies": {
16-
"@babel/eslint-parser": "^7.12.1",
17-
"eslint": "^7.15.0",
18-
"eslint-config-prettier": "^6.15.0",
19-
"eslint-plugin-jest": "^24.1.3",
20-
"prettier": "^2.2.1"
16+
"@babel/core": "^7.15.8",
17+
"@babel/preset-env": "^7.15.8",
18+
"@babel/preset-typescript": "^7.15.0",
19+
"@rollup/plugin-node-resolve": "^13.0.0",
20+
"@rollup/plugin-typescript": "^8.3.0",
21+
"@symfony/stimulus-testing": "^1.1.0",
22+
"@typescript-eslint/eslint-plugin": "^5.2.0",
23+
"@typescript-eslint/parser": "^5.2.0",
24+
"babel-jest": "^27.3.1",
25+
"eslint": "^8.1.0",
26+
"eslint-config-prettier": "^8.0.0",
27+
"eslint-plugin-jest": "^25.2.2",
28+
"jest": "^27.3.1",
29+
"pkg-up": "^3.1.0",
30+
"prettier": "^2.2.1",
31+
"rollup": "^2.52.2",
32+
"tslib": "^2.3.1",
33+
"typescript": "^4.4.4"
2134
},
2235
"eslintConfig": {
2336
"root": true,
24-
"parser": "@babel/eslint-parser",
37+
"parser": "@typescript-eslint/parser",
38+
"plugins": [
39+
"@typescript-eslint"
40+
],
2541
"extends": [
2642
"eslint:recommended",
27-
"prettier"
43+
"prettier",
44+
"plugin:@typescript-eslint/eslint-recommended",
45+
"plugin:@typescript-eslint/recommended"
2846
],
47+
"rules": {
48+
"@typescript-eslint/no-explicit-any": "off"
49+
},
2950
"env": {
3051
"browser": true
3152
},
3253
"overrides": [
3354
{
3455
"files": [
35-
"src/*/Resources/assets/test/*.js"
56+
"src/*/Resources/assets/test/**/*.ts",
57+
"src/*/assets/test/**/*.ts"
3658
],
3759
"extends": [
3860
"plugin:jest/recommended"

rollup.config.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import resolve from '@rollup/plugin-node-resolve';
2+
import typescript from '@rollup/plugin-typescript';
3+
import glob from 'glob';
4+
import path from 'path';
5+
import pkgUp from 'pkg-up';
6+
7+
const files = glob.sync("src/**/assets/src/*controller.ts");
8+
const packages = files.map((file) => {
9+
const absolutePath = path.join(__dirname, file);
10+
const packageData = require(pkgUp.sync({ cwd: absolutePath }));
11+
const peerDependencies = [
12+
'@hotwired/stimulus',
13+
...(packageData.peerDependencies ? Object.keys(packageData.peerDependencies) : [])
14+
];
15+
16+
return {
17+
input: file,
18+
output: {
19+
file: path.join(absolutePath, '..', '..', 'dist', path.basename(file, '.ts') + '.js'),
20+
format: 'esm',
21+
},
22+
external: peerDependencies,
23+
plugins: [
24+
resolve(),
25+
typescript(),
26+
],
27+
};
28+
});
29+
30+
export default packages;

src/Chartjs/Resources/assets/.babelrc

Lines changed: 0 additions & 4 deletions
This file was deleted.
Lines changed: 29 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,32 @@
1-
/*
2-
* This file is part of the Symfony package.
3-
*
4-
* (c) Fabien Potencier <[email protected]>
5-
*
6-
* For the full copyright and license information, please view the LICENSE
7-
* file that was distributed with this source code.
8-
*/
9-
'use strict';
10-
11-
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
12-
13-
Object.defineProperty(exports, "__esModule", {
14-
value: true
15-
});
16-
exports["default"] = void 0;
17-
18-
var _stimulus = require("@hotwired/stimulus");
19-
20-
var _chart = require("chart.js");
21-
22-
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
23-
24-
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
25-
26-
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
27-
28-
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
29-
30-
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
31-
32-
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
33-
34-
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
35-
36-
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
37-
38-
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
39-
40-
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
41-
42-
var _default = /*#__PURE__*/function (_Controller) {
43-
_inherits(_default, _Controller);
44-
45-
var _super = _createSuper(_default);
46-
47-
function _default() {
48-
_classCallCheck(this, _default);
49-
50-
return _super.apply(this, arguments);
51-
}
52-
53-
_createClass(_default, [{
54-
key: "connect",
55-
value: function connect() {
56-
var payload = JSON.parse(this.element.getAttribute('data-view'));
57-
58-
if (Array.isArray(payload.options) && 0 === payload.options.length) {
59-
payload.options = {};
60-
}
61-
62-
this._dispatchEvent('chartjs:pre-connect', {
63-
options: payload.options
64-
});
65-
66-
var chart = new _chart.Chart(this.element.getContext('2d'), payload);
67-
68-
this._dispatchEvent('chartjs:connect', {
69-
chart: chart
70-
});
1+
import { Controller } from '@hotwired/stimulus';
2+
import { Chart } from 'chart.js';
3+
4+
class controller extends Controller {
5+
connect() {
6+
if (!(this.element instanceof HTMLCanvasElement)) {
7+
throw new Error('Invalid element');
8+
}
9+
const viewData = this.element.getAttribute('data-view');
10+
if (!viewData) {
11+
throw new Error('Missing data-view attribute.');
12+
}
13+
const payload = JSON.parse(viewData);
14+
if (Array.isArray(payload.options) && 0 === payload.options.length) {
15+
payload.options = {};
16+
}
17+
this._dispatchEvent('chartjs:pre-connect', { options: payload.options });
18+
const canvasContext = this.element.getContext('2d');
19+
if (!canvasContext) {
20+
throw new Error('Could not getContext() from Element');
21+
}
22+
const chart = new Chart(canvasContext, payload);
23+
this._dispatchEvent('chartjs:connect', { chart });
7124
}
72-
}, {
73-
key: "_dispatchEvent",
74-
value: function _dispatchEvent(name) {
75-
var payload = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
76-
var canBubble = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
77-
var cancelable = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
78-
var userEvent = document.createEvent('CustomEvent');
79-
userEvent.initCustomEvent(name, canBubble, cancelable, payload);
80-
this.element.dispatchEvent(userEvent);
25+
_dispatchEvent(name, payload = null, canBubble = false, cancelable = false) {
26+
const userEvent = document.createEvent('CustomEvent');
27+
userEvent.initCustomEvent(name, canBubble, cancelable, payload);
28+
this.element.dispatchEvent(userEvent);
8129
}
82-
}]);
83-
84-
return _default;
85-
}(_stimulus.Controller);
30+
}
8631

87-
exports["default"] = _default;
32+
export { controller as default };
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const config = require('../../../../jest.config.js');
2+
3+
config.setupFilesAfterEnv.push('./test/setup.js');
4+
5+
module.exports = config;

src/Chartjs/Resources/assets/package.json

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,14 @@
1313
}
1414
}
1515
},
16-
"scripts": {
17-
"build": "babel src -d dist",
18-
"test": "babel src -d dist && jest",
19-
"lint": "eslint src test"
20-
},
2116
"peerDependencies": {
22-
"chart.js": "^2.9.4",
23-
"@hotwired/stimulus": "^3.0.0"
17+
"@hotwired/stimulus": "^3.0.0",
18+
"chart.js": "^2.9.4"
2419
},
2520
"devDependencies": {
26-
"@babel/cli": "^7.12.1",
27-
"@babel/core": "^7.12.3",
28-
"@babel/plugin-proposal-class-properties": "^7.12.1",
29-
"@babel/preset-env": "^7.12.7",
30-
"@symfony/stimulus-testing": "^1.1.0",
21+
"@hotwired/stimulus": "^3.0.0",
22+
"@types/chart.js": "^2.9.34",
3123
"chart.js": "^2.9.4",
32-
"jest-canvas-mock": "^2.3.0",
33-
"@hotwired/stimulus": "^3.0.0"
34-
},
35-
"jest": {
36-
"testRegex": "test/.*\\.test.js",
37-
"setupFilesAfterEnv": [
38-
"./test/setup.js"
39-
]
24+
"jest-canvas-mock": "^2.3.0"
4025
}
4126
}

src/Chartjs/Resources/assets/src/controller.js renamed to src/Chartjs/Resources/assets/src/controller.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,32 @@ import { Chart } from 'chart.js';
1414

1515
export default class extends Controller {
1616
connect() {
17-
const payload = JSON.parse(this.element.getAttribute('data-view'));
17+
if (!(this.element instanceof HTMLCanvasElement)) {
18+
throw new Error('Invalid element');
19+
}
20+
21+
const viewData = this.element.getAttribute('data-view');
22+
if (!viewData) {
23+
throw new Error('Missing data-view attribute.');
24+
}
25+
26+
const payload = JSON.parse(viewData);
1827
if (Array.isArray(payload.options) && 0 === payload.options.length) {
1928
payload.options = {};
2029
}
2130

2231
this._dispatchEvent('chartjs:pre-connect', { options: payload.options });
2332

24-
const chart = new Chart(this.element.getContext('2d'), payload);
33+
const canvasContext = this.element.getContext('2d');
34+
if (!canvasContext) {
35+
throw new Error('Could not getContext() from Element');
36+
}
37+
const chart = new Chart(canvasContext, payload);
2538

2639
this._dispatchEvent('chartjs:connect', { chart });
2740
}
2841

29-
_dispatchEvent(name, payload = null, canBubble = false, cancelable = false) {
42+
_dispatchEvent(name: string, payload: any = null, canBubble = false, cancelable = false) {
3043
const userEvent = document.createEvent('CustomEvent');
3144
userEvent.initCustomEvent(name, canBubble, cancelable, payload);
3245

src/Chartjs/Resources/assets/test/controller.test.js renamed to src/Chartjs/Resources/assets/test/controller.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import { Application, Controller } from '@hotwired/stimulus';
1313
import { getByTestId, waitFor } from '@testing-library/dom';
1414
import { clearDOM, mountDOM } from '@symfony/stimulus-testing';
15-
import ChartjsController from '../dist/controller';
15+
import ChartjsController from '../src/controller';
1616

1717
// Controller used to check the actual controller was properly booted
1818
class CheckController extends Controller {

src/Chartjs/Resources/assets/test/setup.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,4 @@
99

1010
'use strict';
1111

12-
import '@symfony/stimulus-testing/setup';
1312
import 'jest-canvas-mock';

src/Cropperjs/Resources/assets/.babelrc

Lines changed: 0 additions & 4 deletions
This file was deleted.

0 commit comments

Comments
 (0)