Skip to content

Outputting Typescript types #609

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ jobs:
- run: yarn check-format

js-dist-current:
# always skip check for now - building is too inefficient and large for CI
if: false
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
Expand Down
11 changes: 5 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"private": true,
"workspaces": [
"src/**/assets"
"src/*/assets"
],
"scripts": {
"build": "yarn rollup -c",
Expand All @@ -16,9 +16,9 @@
"@babel/preset-env": "^7.15.8",
"@babel/preset-react": "^7.15.8",
"@babel/preset-typescript": "^7.15.8",
"@rollup/plugin-commonjs": "^22.0.0",
"@rollup/plugin-node-resolve": "^13.0.6",
"@rollup/plugin-typescript": "^8.3.0",
"@rollup/plugin-commonjs": "^23.0.0",
"@rollup/plugin-node-resolve": "^15.0.0",
"@rollup/plugin-typescript": "^10.0.0",
"@symfony/stimulus-testing": "^2.0.1",
"@typescript-eslint/eslint-plugin": "^5.2.0",
"@typescript-eslint/parser": "^5.2.0",
Expand All @@ -27,9 +27,8 @@
"eslint-config-prettier": "^8.0.0",
"eslint-plugin-jest": "^25.2.2",
"jest": "^27.3.1",
"pkg-up": "^3.1.0",
"prettier": "^2.2.1",
"rollup": "^2.68.0",
"rollup": "^3.7.0",
"tslib": "^2.3.1",
"typescript": "^4.4.4"
},
Expand Down
59 changes: 45 additions & 14 deletions rollup.config.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import typescript from '@rollup/plugin-typescript';
import glob from 'glob';
import path from 'path';
import pkgUp from 'pkg-up';
const resolve = require('@rollup/plugin-node-resolve');
const commonjs = require('@rollup/plugin-commonjs');
const typescript = require('@rollup/plugin-typescript');
const fs = require('fs');
const glob = require('glob');
const path = require('path');

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

/**
* Moves the generated TypeScript declaration files to the correct location.
*
* This could probably be configured in the TypeScript plugin.
*/
const moveTypescriptDeclarationsPlugin = (packagePath) => ({
name: 'move-ts-declarations',
writeBundle: async () => {
const files = glob.sync(path.join(packagePath, 'dist', '*', 'assets', 'src', '**/*.d.ts'));
files.forEach((file) => {
// a bit odd, but remove first 7 directories, which will leave
// only the relative path to the file
const relativePath = file.split('/').slice(7).join('/');

const targetFile = path.join(packagePath, 'dist', relativePath);
if (!fs.existsSync(path.dirname(targetFile))) {
fs.mkdirSync(path.dirname(targetFile), { recursive: true });
}
fs.renameSync(file, targetFile);
});
}
});

const files = glob.sync('src/*/assets/src/*controller.ts');
const packages = files.map((file) => {
const absolutePath = path.join(__dirname, file);
const packageData = require(pkgUp.sync({ cwd: absolutePath }));
module.exports = files.map((file) => {
const packageRoot = path.join(file, '..', '..');
const packagePath = path.join(packageRoot, 'package.json');
const packageData = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
const peerDependencies = [
'@hotwired/stimulus',
...(packageData.peerDependencies ? Object.keys(packageData.peerDependencies) : [])
Expand All @@ -50,21 +74,28 @@ const packages = files.map((file) => {
return {
input: file,
output: {
file: path.join(absolutePath, '..', '..', 'dist', path.basename(file, '.ts') + '.js'),
file: path.join(packageRoot, 'dist', path.basename(file, '.ts') + '.js'),
format: 'esm',
},
external: peerDependencies,
plugins: [
resolve(),
typescript(),
typescript({
filterRoot: packageRoot,
include: ['src/**/*.ts'],
compilerOptions: {
outDir: 'dist',
declaration: true,
emitDeclarationOnly: true,
}
}),
commonjs({
namedExports: {
'react-dom/client': ['createRoot'],
},
}),
wildcardExternalsPlugin(peerDependencies)
wildcardExternalsPlugin(peerDependencies),
moveTypescriptDeclarationsPlugin(packageRoot),
],
};
});

export default packages;
29 changes: 29 additions & 0 deletions src/Autocomplete/assets/dist/controller.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Controller } from '@hotwired/stimulus';
import TomSelect from 'tom-select';
export default class extends Controller {
#private;
static values: {
url: StringConstructor;
optionsAsHtml: BooleanConstructor;
noResultsFoundText: StringConstructor;
noMoreResultsText: StringConstructor;
minCharacters: NumberConstructor;
tomSelectOptions: ObjectConstructor;
preload: StringConstructor;
};
readonly urlValue: string;
readonly optionsAsHtmlValue: boolean;
readonly noMoreResultsTextValue: string;
readonly noResultsFoundTextValue: string;
readonly minCharactersValue: number;
readonly tomSelectOptionsValue: object;
readonly hasPreloadValue: boolean;
readonly preloadValue: string;
tomSelect: TomSelect;
initialize(): void;
connect(): void;
disconnect(): void;
get selectElement(): HTMLSelectElement | null;
get formElement(): HTMLInputElement | HTMLSelectElement;
get preload(): string | boolean;
}
46 changes: 23 additions & 23 deletions src/Autocomplete/assets/dist/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ function __classPrivateFieldGet(receiver, state, kind, f) {
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
}

var _instances, _getCommonConfig, _createAutocomplete, _createAutocompleteWithHtmlContents, _createAutocompleteWithRemoteData, _stripTags, _mergeObjects, _createTomSelect, _dispatchEvent;
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;
class default_1 extends Controller {
constructor() {
super(...arguments);
_instances.add(this);
_default_1_instances.add(this);
}
initialize() {
this.element.setAttribute('data-live-ignore', '');
Expand All @@ -39,14 +39,14 @@ class default_1 extends Controller {
}
connect() {
if (this.urlValue) {
this.tomSelect = __classPrivateFieldGet(this, _instances, "m", _createAutocompleteWithRemoteData).call(this, this.urlValue, this.minCharactersValue);
this.tomSelect = __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_createAutocompleteWithRemoteData).call(this, this.urlValue, this.minCharactersValue);
return;
}
if (this.optionsAsHtmlValue) {
this.tomSelect = __classPrivateFieldGet(this, _instances, "m", _createAutocompleteWithHtmlContents).call(this);
this.tomSelect = __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_createAutocompleteWithHtmlContents).call(this);
return;
}
this.tomSelect = __classPrivateFieldGet(this, _instances, "m", _createAutocomplete).call(this);
this.tomSelect = __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_createAutocomplete).call(this);
}
disconnect() {
this.tomSelect.revertSettings.innerHTML = this.element.innerHTML;
Expand Down Expand Up @@ -77,7 +77,7 @@ class default_1 extends Controller {
return this.preloadValue;
}
}
_instances = new WeakSet(), _getCommonConfig = function _getCommonConfig() {
_default_1_instances = new WeakSet(), _default_1_getCommonConfig = function _default_1_getCommonConfig() {
const plugins = {};
const isMultiple = !this.selectElement || this.selectElement.multiple;
if (!this.formElement.disabled && !isMultiple) {
Expand Down Expand Up @@ -109,19 +109,19 @@ _instances = new WeakSet(), _getCommonConfig = function _getCommonConfig() {
if (!this.selectElement && !this.urlValue) {
config.shouldLoad = () => false;
}
return __classPrivateFieldGet(this, _instances, "m", _mergeObjects).call(this, config, this.tomSelectOptionsValue);
}, _createAutocomplete = function _createAutocomplete() {
const config = __classPrivateFieldGet(this, _instances, "m", _mergeObjects).call(this, __classPrivateFieldGet(this, _instances, "m", _getCommonConfig).call(this), {
return __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_mergeObjects).call(this, config, this.tomSelectOptionsValue);
}, _default_1_createAutocomplete = function _default_1_createAutocomplete() {
const config = __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_mergeObjects).call(this, __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_getCommonConfig).call(this), {
maxOptions: this.selectElement ? this.selectElement.options.length : 50,
});
return __classPrivateFieldGet(this, _instances, "m", _createTomSelect).call(this, config);
}, _createAutocompleteWithHtmlContents = function _createAutocompleteWithHtmlContents() {
const config = __classPrivateFieldGet(this, _instances, "m", _mergeObjects).call(this, __classPrivateFieldGet(this, _instances, "m", _getCommonConfig).call(this), {
return __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_createTomSelect).call(this, config);
}, _default_1_createAutocompleteWithHtmlContents = function _default_1_createAutocompleteWithHtmlContents() {
const config = __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_mergeObjects).call(this, __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_getCommonConfig).call(this), {
maxOptions: this.selectElement ? this.selectElement.options.length : 50,
score: (search) => {
const scoringFunction = this.tomSelect.getScoreFunction(search);
return (item) => {
return scoringFunction(Object.assign(Object.assign({}, item), { text: __classPrivateFieldGet(this, _instances, "m", _stripTags).call(this, item.text) }));
return scoringFunction(Object.assign(Object.assign({}, item), { text: __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_stripTags).call(this, item.text) }));
};
},
render: {
Expand All @@ -133,9 +133,9 @@ _instances = new WeakSet(), _getCommonConfig = function _getCommonConfig() {
},
},
});
return __classPrivateFieldGet(this, _instances, "m", _createTomSelect).call(this, config);
}, _createAutocompleteWithRemoteData = function _createAutocompleteWithRemoteData(autocompleteEndpointUrl, minCharacterLength) {
const config = __classPrivateFieldGet(this, _instances, "m", _mergeObjects).call(this, __classPrivateFieldGet(this, _instances, "m", _getCommonConfig).call(this), {
return __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_createTomSelect).call(this, config);
}, _default_1_createAutocompleteWithRemoteData = function _default_1_createAutocompleteWithRemoteData(autocompleteEndpointUrl, minCharacterLength) {
const config = __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_mergeObjects).call(this, __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_getCommonConfig).call(this), {
firstUrl: (query) => {
const separator = autocompleteEndpointUrl.includes('?') ? '&' : '?';
return `${autocompleteEndpointUrl}${separator}query=${encodeURIComponent(query)}`;
Expand Down Expand Up @@ -175,17 +175,17 @@ _instances = new WeakSet(), _getCommonConfig = function _getCommonConfig() {
},
preload: this.preload,
});
return __classPrivateFieldGet(this, _instances, "m", _createTomSelect).call(this, config);
}, _stripTags = function _stripTags(string) {
return __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_createTomSelect).call(this, config);
}, _default_1_stripTags = function _default_1_stripTags(string) {
return string.replace(/(<([^>]+)>)/gi, '');
}, _mergeObjects = function _mergeObjects(object1, object2) {
}, _default_1_mergeObjects = function _default_1_mergeObjects(object1, object2) {
return Object.assign(Object.assign({}, object1), object2);
}, _createTomSelect = function _createTomSelect(options) {
__classPrivateFieldGet(this, _instances, "m", _dispatchEvent).call(this, 'autocomplete:pre-connect', { options });
}, _default_1_createTomSelect = function _default_1_createTomSelect(options) {
__classPrivateFieldGet(this, _default_1_instances, "m", _default_1_dispatchEvent).call(this, 'autocomplete:pre-connect', { options });
const tomSelect = new TomSelect(this.formElement, options);
__classPrivateFieldGet(this, _instances, "m", _dispatchEvent).call(this, 'autocomplete:connect', { tomSelect, options });
__classPrivateFieldGet(this, _default_1_instances, "m", _default_1_dispatchEvent).call(this, 'autocomplete:connect', { tomSelect, options });
return tomSelect;
}, _dispatchEvent = function _dispatchEvent(name, payload) {
}, _default_1_dispatchEvent = function _default_1_dispatchEvent(name, payload) {
this.element.dispatchEvent(new CustomEvent(name, { detail: payload, bubbles: true }));
};
default_1.values = {
Expand Down
2 changes: 1 addition & 1 deletion src/Autocomplete/assets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@symfony/ux-autocomplete",
"description": "JavaScript-powered autocompletion functionality for forms.",
"main": "dist/controller.js",
"module": "dist/controller.js",
"types": "dist/controller.d.ts",
"version": "1.0.0",
"license": "MIT",
"symfony": {
Expand Down
9 changes: 9 additions & 0 deletions src/Chartjs/assets/dist/controller.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
readonly viewValue: any;
static values: {
view: ObjectConstructor;
};
connect(): void;
_dispatchEvent(name: string, payload: any): void;
}
2 changes: 2 additions & 0 deletions src/Chartjs/assets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
"description": "Chart.js integration for Symfony",
"license": "MIT",
"version": "1.1.0",
"main": "dist/controller.js",
"types": "dist/controller.d.ts",
"symfony": {
"controllers": {
"chart": {
Expand Down
11 changes: 11 additions & 0 deletions src/Cropperjs/assets/dist/controller.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Controller } from '@hotwired/stimulus';
export default class CropperController extends Controller {
readonly publicUrlValue: string;
readonly optionsValue: object;
static values: {
publicUrl: StringConstructor;
options: ObjectConstructor;
};
connect(): void;
_dispatchEvent(name: string, payload: any): void;
}
2 changes: 2 additions & 0 deletions src/Cropperjs/assets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
"description": "Cropper.js integration for Symfony",
"license": "MIT",
"version": "1.1.0",
"main": "dist/controller.js",
"types": "dist/controller.d.ts",
"symfony": {
"controllers": {
"cropper": {
Expand Down
15 changes: 15 additions & 0 deletions src/Dropzone/assets/dist/controller.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
readonly inputTarget: HTMLInputElement;
readonly placeholderTarget: HTMLDivElement;
readonly previewTarget: HTMLDivElement;
readonly previewClearButtonTarget: HTMLButtonElement;
readonly previewFilenameTarget: HTMLDivElement;
readonly previewImageTarget: HTMLDivElement;
static targets: string[];
connect(): void;
clear(): void;
onInputChange(event: any): void;
_populateImagePreview(file: Blob): void;
_dispatchEvent(name: string, payload?: any): void;
}
2 changes: 2 additions & 0 deletions src/Dropzone/assets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
"description": "File input dropzones for Symfony Forms",
"license": "MIT",
"version": "1.1.0",
"main": "dist/controller.js",
"types": "dist/controller.d.ts",
"symfony": {
"controllers": {
"dropzone": {
Expand Down
13 changes: 13 additions & 0 deletions src/LazyImage/assets/dist/controller.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
readonly srcValue: string;
readonly srcsetValue: any;
readonly hasSrcsetValue: boolean;
static values: {
src: StringConstructor;
srcset: ObjectConstructor;
};
connect(): void;
_calculateSrcsetString(): string;
_dispatchEvent(name: string, payload: any): void;
}
2 changes: 2 additions & 0 deletions src/LazyImage/assets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
"description": "Lazy image loader and utilities for Symfony",
"license": "MIT",
"version": "1.1.0",
"main": "dist/controller.js",
"types": "dist/controller.d.ts",
"symfony": {
"controllers": {
"lazy-image": {
Expand Down
15 changes: 15 additions & 0 deletions src/LiveComponent/assets/dist/Backend.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import BackendRequest from './BackendRequest';
export interface BackendInterface {
makeRequest(data: any, actions: BackendAction[], updatedModels: string[], childrenFingerprints: any): BackendRequest;
}
export interface BackendAction {
name: string;
args: Record<string, string>;
}
export default class implements BackendInterface {
private url;
private readonly csrfToken;
constructor(url: string, csrfToken?: string | null);
makeRequest(data: any, actions: BackendAction[], updatedModels: string[], childrenFingerprints: any): BackendRequest;
private willDataFitInUrl;
}
9 changes: 9 additions & 0 deletions src/LiveComponent/assets/dist/BackendRequest.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export default class {
promise: Promise<Response>;
actions: string[];
updatedModels: string[];
isResolved: boolean;
constructor(promise: Promise<Response>, actions: string[], updateModels: string[]);
containsOneOfActions(targetedActions: string[]): boolean;
areAnyModelsUpdated(targetedModels: string[]): boolean;
}
6 changes: 6 additions & 0 deletions src/LiveComponent/assets/dist/BackendResponse.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default class {
response: Response;
private body;
constructor(response: Response);
getBody(): Promise<string>;
}
Loading