chore(generator-superset): migrate to monorepo (#17829)

* chore(generator-superset): migrate to monorepo

* add todo and remove webpack reference from template

* fix linting errors

* remove redundant test file
This commit is contained in:
Ville Brofeldt 2021-12-21 11:44:21 +02:00 committed by GitHub
parent d5768ab649
commit 19daf65b54
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 133 additions and 332 deletions

View File

@ -27,36 +27,13 @@ module.exports = class extends Generator {
async prompting() {
// Have Yeoman greet the user.
this.log(
yosay(`Welcome to the rad ${chalk.red('generator-superset')} generator!`),
yosay(`Welcome to the ${chalk.red('generator-superset')} generator!`),
);
this.option('skipInstall');
this.answers = await this.prompt([
{
type: 'list',
name: 'subgenerator',
message: 'What do you want to do?',
choices: [
{
name: 'Create superset-ui core package',
value: 'package',
},
{
name: 'Create superset-ui chart plugin package',
value: 'plugin-chart',
},
],
},
]);
}
configuring() {
// Redirect the default 'app' generator
// to 'package' subgenerator
// until there are multiple subgenerators
// then this can be changed into a menu to select
// subgenerator.
this.composeWith(require.resolve(`../${this.answers.subgenerator}`));
this.composeWith(require.resolve(`../plugin-chart`));
}
};

View File

@ -1,78 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* eslint-disable sort-keys */
const Generator = require('yeoman-generator');
const _ = require('lodash');
module.exports = class extends Generator {
async prompting() {
this.option('skipInstall');
this.answers = await this.prompt([
{
type: 'input',
name: 'name',
message: 'Package name:',
default: _.kebabCase(this.appname.replace('superset ui', '').trim()), // Default to current folder name
},
{
type: 'list',
name: 'language',
message: 'Choose language',
default: 'typescript',
choices: [
{
name: 'typescript',
value: 'typescript',
short: 't',
},
{
name: 'javascript',
value: 'javascript',
short: 'j',
},
],
},
]);
}
writing() {
this.fs.copyTpl(
this.templatePath('_package.json'),
this.destinationPath('package.json'),
this.answers,
);
this.fs.copyTpl(
this.templatePath('README.md'),
this.destinationPath('README.md'),
this.answers,
);
const ext = this.answers.language === 'typescript' ? 'ts' : 'js';
this.fs.copy(
this.templatePath('src/index.txt'),
this.destinationPath(`src/index.${ext}`),
);
this.fs.copy(
this.templatePath('test/index.txt'),
this.destinationPath(`test/index.test.${ext}`),
);
}
};

View File

@ -1,46 +0,0 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
## @superset-ui/<%= name %>
[![Version](https://img.shields.io/npm/v/@superset-ui/<%= name
%>.svg?style=flat)](https://img.shields.io/npm/v/@superset-ui/<%= name %>.svg?style=flat)
[![David (path)](https://img.shields.io/david/apache-superset/superset-ui.svg?path=packages%2Fsuperset-ui-<%=
name
%>&style=flat-square)](https://david-dm.org/apache-superset/superset-ui?path=packages/superset-ui-<%=
name %>)
Description
#### Example usage
```js
import { xxx } from '@superset-ui/<%= name %>';
```
#### API
`fn(args)`
- Do something
### Development
`@data-ui/build-config` is used to manage the build configuration for this package including babel
builds, jest testing, eslint, and prettier.

View File

@ -1,23 +0,0 @@
{
"name": "@superset-ui/<%= name %>",
"version": "0.0.0",
"description": "Superset UI <%= name %>",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"files": ["esm", "lib"],
"repository": {
"type": "git",
"url": "git+https://github.com/apache-superset/superset-ui.git"
},
"keywords": ["superset"],
"author": "Superset",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/apache-superset/superset-ui/issues"
},
"homepage": "https://github.com/apache-superset/superset-ui#readme",
"publishConfig": {
"access": "public"
}
}

View File

@ -1,2 +0,0 @@
const x = 1;
export default x;

View File

@ -1,5 +0,0 @@
describe('My Test', () => {
it('tests something', () => {
expect(1).toEqual(1);
});
});

View File

@ -32,7 +32,9 @@ module.exports = class extends Generator {
name: 'packageName',
message: 'Package name:',
// Default to current folder name
default: _.kebabCase(this.appname.replace('plugin chart', '').trim()),
default: _.kebabCase(
this.appname.replace('superset plugin chart', '').trim(),
),
},
{
type: 'input',
@ -40,24 +42,9 @@ module.exports = class extends Generator {
message: 'Description:',
// Default to current folder name
default: _.upperFirst(
_.startCase(this.appname.replace('plugin chart', '').trim()),
_.startCase(this.appname.replace('superset plugin chart', '').trim()),
),
},
{
type: 'list',
name: 'componentType',
message: 'What type of React component would you like?',
choices: [
{
name: 'Class component',
value: 'class',
},
{
name: 'Function component (with hooks)',
value: 'function',
},
],
},
{
type: 'list',
name: 'chartType',
@ -73,12 +60,6 @@ module.exports = class extends Generator {
},
],
},
{
type: 'confirm',
name: 'addBadges',
message: "Add superset-ui badges to your plugin's README.md",
default: true,
},
]);
}
@ -96,9 +77,11 @@ module.exports = class extends Generator {
};
[
['babel.config.erb', 'babel.config.js'],
['jest.config.erb', 'jest.config.js'],
['package.erb', 'package.json'],
['tsconfig.json', 'tsconfig.json'],
['README.erb', 'README.md'],
['tsconfig.json', 'tsconfig.json'],
['src/index.erb', 'src/index.ts'],
['src/plugin/buildQuery.erb', 'src/plugin/buildQuery.ts'],
['src/plugin/controlPanel.erb', 'src/plugin/controlPanel.ts'],
@ -107,6 +90,10 @@ module.exports = class extends Generator {
['src/types.erb', 'src/types.ts'],
['src/MyChart.erb', `src/${packageLabel}.tsx`],
['test/index.erb', 'test/index.test.ts'],
[
'test/__mocks__/mockExportString.js',
'test/__mocks__/mockExportString.js',
],
['test/plugin/buildQuery.test.erb', 'test/plugin/buildQuery.test.ts'],
[
'test/plugin/transformProps.test.erb',

View File

@ -1,6 +1,4 @@
## @superset-ui/plugin-chart-<%= packageName %>
<%if (addBadges) { %>[![Version](https://img.shields.io/npm/v/@superset-ui/plugin-chart-<%= packageName %>.svg?style=flat-square)](https://www.npmjs.com/package/@superset-ui/plugin-chart-<%= packageName %>)<% } %>
## superset-plugin-chart-<%= packageName %>
This plugin provides <%= description %> for Superset.

View File

@ -0,0 +1,20 @@
const { getConfig } = require('@airbnb/config-babel');
const config = getConfig({
library: true,
react: true,
next: true,
esm: process.env.BABEL_OUTPUT === 'esm',
node: process.env.NODE_ENV === 'test',
typescript: true,
env: {
targets: { esmodules: true },
},
});
config.plugins = [
['babel-plugin-transform-dev', { evaluate: false }],
['babel-plugin-typescript-to-proptypes', { loose: true }],
['@babel/plugin-proposal-class-properties', { loose: true }],
];
module.exports = config;

View File

@ -0,0 +1,6 @@
module.exports = {
moduleFileExtensions: ['mock.js', 'ts', 'tsx', 'js', 'jsx', 'json', 'node'],
moduleNameMapper: {
'\\.(gif|ttf|eot|png|jpg)$': '<rootDir>/test/__mocks__/mockExportString.js',
},
};

View File

@ -1,6 +1,6 @@
{
"name": "@superset-ui/plugin-chart-<%= packageName %>",
"version": "0.0.0",
"name": "superset-plugin-chart-<%= packageName %>",
"version": "0.1.0",
"description": "Superset Chart - <%= description %>",
"sideEffects": false,
"main": "lib/index.js",
@ -9,31 +9,38 @@
"esm",
"lib"
],
"repository": {
"type": "git",
"url": "git+https://github.com/apache-superset/superset-ui.git"
"scripts": {
"build": "npm run build-cjs && npm run build-esm && npm run ts-types",
"build-cjs": "babel src --extensions \".ts,.tsx,.js,.jsx\" --copy-files --out-dir lib",
"build-clean": "npm run clean && npm run build",
"build-esm": "BABEL_OUTPUT=esm babel src --extensions \".ts,.tsx,.js,.jsx\" --copy-files --out-dir esm",
"clean": "rm -rf {lib,esm,tsconfig.tsbuildinfo}",
"dev": "webpack --mode=development --color --watch",
"ts-types": "tsc --build",
"test": "jest"
},
"keywords": [
"superset"
],
"author": "Superset",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/apache-superset/superset-ui/issues"
},
"homepage": "https://github.com/apache-superset/superset-ui#readme",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@superset-ui/core": "^0.17.40",
"@superset-ui/chart-controls": "^0.17.41"
"@superset-ui/core": "^0.18.25",
"@superset-ui/chart-controls": "^0.18.25"
},
"peerDependencies": {
"react": "^16.13.1"
},
"devDependencies": {
"@types/jest": "^26.0.0",
"jest": "^26.0.1"
"@airbnb/config-babel": "^2.0.1",
"@babel/cli": "^7.16.0",
"@types/jest": "^26.0.4",
"babel-loader": "^8.2.2",
"clean-webpack-plugin": "^4.0.0",
"jest": "^26.6.3",
"thread-loader": "^3.0.4",
"ts-loader": "^9.2.5",
"typescript": "^4.1.2",
"url-loader": "^4.1.1"
}
}

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
import React, { <%if (componentType == 'class') { %>PureComponent<% } %><%if (componentType == 'function') { %>useEffect<% } %>, createRef } from 'react';
import React, { useEffect, createRef } from 'react';
import { styled } from '@superset-ui/core';
import { <%= packageLabel %>Props, <%= packageLabel %>StylesProps } from './types';
@ -50,39 +50,7 @@ const Styles = styled.div<<%= packageLabel %>StylesProps>`
* * FormData (your controls!) provided as props by transformProps.ts
*/
<%if (componentType == 'class') { %>export default class <%= packageLabel %> extends PureComponent<<%= packageLabel %>Props> {
// Often, you just want to get a hold of the DOM and go nuts.
// Here, you can do that with createRef, and componentDidMount.
rootElem = createRef<HTMLDivElement>();
componentDidMount() {
const root = this.rootElem.current as HTMLElement;
console.log('Plugin element', root);
}
render() {
// height and width are the height and width of the DOM element as it exists in the dashboard.
// There is also a `data` prop, which is, of course, your DATA 🎉
console.log('Approach 1 props', this.props);
const { data, height, width } = this.props;
console.log('Plugin props', this.props);
return (
<Styles
ref={this.rootElem}
boldText={this.props.boldText}
headerFontSize={this.props.headerFontSize}
height={height}
width={width}
>
<h3>{this.props.headerText}</h3>
<pre>{JSON.stringify(data, null, 2)}</pre>
</Styles>
);
}
}<% } %><%if (componentType == 'function') { %>export default function <%= packageLabel %>(props: <%= packageLabel %>Props) {
export default function <%= packageLabel %>(props: <%= packageLabel %>Props) {
// height and width are the height and width of the DOM element as it exists in the dashboard.
// There is also a `data` prop, which is, of course, your DATA 🎉
const { data, height, width } = props;
@ -110,4 +78,4 @@ const Styles = styled.div<<%= packageLabel %>StylesProps>`
<pre>${JSON.stringify(data, null, 2)}</pre>
</Styles>
);
}<% } %>
}

View File

@ -0,0 +1,19 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
module.exports = 'test-file-stub';

View File

@ -29,6 +29,6 @@ describe('<%= packageLabel %> buildQuery', () => {
it('should build groupby with series in form data', () => {
const queryContext = buildQuery(formData);
const [query] = queryContext.queries;
expect(query.groupby).toEqual(['foo']);
expect(query.columns).toEqual(['foo']);
});
});

View File

@ -1,25 +1,44 @@
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"declaration": true,
"declarationDir": "lib",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": false,
"jsx": "react",
"lib": [
"dom",
"esnext"
],
"module": "esnext",
"moduleResolution": "node",
"noEmitOnError": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"outDir": "lib",
"rootDir": "src"
"pretty": true,
"removeComments": false,
"strict": true,
"target": "es2015",
"useDefineForClassFields": false,
"composite": true,
"declarationMap": true,
"rootDir": "src",
"skipLibCheck": true,
"emitDeclarationOnly": true,
"resolveJsonModule": true,
"types": ["jest"],
"typeRoots": [
"./node_modules/@types"
]
},
"exclude": [
"lib",
"test"
],
"extends": "../../tsconfig.json",
"include": [
"src/**/*",
"types/**/*",
"../../types/**/*"
],
"references": [
{
"path": "../../packages/superset-ui-chart-controls"
},
{
"path": "../../packages/superset-ui-core"
}
"types/**/*"
]
}

View File

@ -1,60 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
const path = require('path');
const assert = require('yeoman-assert');
const helpers = require('yeoman-test');
const fs = require('fs-extra');
const packageModule = require('../generators/package');
test('generator-superset:package:creates typescript files', () =>
helpers
.run(packageModule)
.inTmpDir(function (dir) {
// `dir` is the path to the new temporary directory
fs.copySync(path.join(__dirname, '../generators/package'), dir);
})
.withPrompts({ name: 'my-package', language: 'typescript' })
.withOptions({ skipInstall: true })
.then(function () {
assert.file([
'package.json',
'README.md',
'src/index.ts',
'test/index.test.ts',
]);
}));
test('generator-superset:package:creates javascript files', () =>
helpers
.run(packageModule)
.inTmpDir(function (dir) {
// `dir` is the path to the new temporary directory
fs.copySync(path.join(__dirname, '../generators/package'), dir);
})
.withPrompts({ name: 'my-package', language: 'javascript' })
.withOptions({ skipInstall: true })
.then(function () {
assert.file([
'package.json',
'README.md',
'src/index.js',
'test/index.test.js',
]);
}));

View File

@ -40,6 +40,8 @@ test('generator-superset:plugin-chart:creates files', () =>
.withOptions({ skipInstall: true })
.then(function () {
assert.file([
'babel.config.js',
'jest.config.js',
'package.json',
'README.md',
'src/plugin/buildQuery.ts',
@ -49,6 +51,7 @@ test('generator-superset:plugin-chart:creates files', () =>
'src/ColdMap.tsx',
'src/index.ts',
'test/index.test.ts',
'test/__mocks__/mockExportString.js',
'test/plugin/buildQuery.test.ts',
'test/plugin/transformProps.test.ts',
'types/external.d.ts',

View File

@ -283,7 +283,9 @@ const config = {
},
resolve: {
modules: [APP_DIR, 'node_modules', ROOT_DIR],
alias: {},
alias: {
react: path.resolve('./node_modules/react'),
},
extensions: ['.ts', '.tsx', '.js', '.jsx', '.yml'],
fallback: {
fs: false,
@ -422,7 +424,16 @@ const config = {
// find all the symlinked plugins and use their source code for imports
Object.entries(packageConfig.dependencies).forEach(([pkg, version]) => {
const srcPath = `./node_modules/${pkg}/src`;
if (/^@superset-ui/.test(pkg) && fs.existsSync(srcPath)) {
if (/^superset-plugin-/.test(pkg) && fs.existsSync(srcPath)) {
console.log(
`[Superset External Plugin] Use symlink source for ${pkg} @ ${version}`,
);
// TODO: remove alias once React has been upgraaded to v. 17
config.resolve.alias[pkg] = path.resolve(
APP_DIR,
`node_modules/${pkg}/src`,
);
} else if (/^@superset-ui/.test(pkg) && fs.existsSync(srcPath)) {
console.log(`[Superset Plugin] Use symlink source for ${pkg} @ ${version}`);
// only allow exact match so imports like `@superset-ui/plugin-name/lib`
// and `@superset-ui/plugin-name/esm` can still work.