Add generators for typescript

This commit is contained in:
Convly 2022-03-14 14:54:44 +01:00
parent f5cf8cd976
commit b373282f85
111 changed files with 765 additions and 44 deletions

View File

@ -1,7 +1,7 @@
'use strict';
const path = require('path');
const tsUtils = require('../utils/typescript');
const tsUtils = require('@strapi/typescript-utils');
const { buildAdmin, buildTypeScript } = require('./builders');
/**

View File

@ -1,6 +1,6 @@
'use strict';
const tsUtils = require('../../utils/typescript');
const tsUtils = require('@strapi/typescript-utils');
module.exports = async ({ srcDir, watch = false }) => {
const isTSProject = await tsUtils.isTypeScriptProject(srcDir);

View File

@ -7,10 +7,10 @@ const chokidar = require('chokidar');
const execa = require('execa');
const { getOr } = require('lodash/fp');
const { joinBy } = require('@strapi/utils');
const tsUtils = require('@strapi/typescript-utils');
const loadConfiguration = require('../core/app-configuration');
const strapi = require('../index');
const tsUtils = require('../utils/typescript');
const { buildTypeScript, buildAdmin } = require('./builders');
/**

View File

@ -2,10 +2,11 @@
const path = require('path');
const strapiAdmin = require('@strapi/admin');
const tsUtils = require('@strapi/typescript-utils');
const { getConfigUrls, getAbsoluteServerUrl } = require('@strapi/utils');
const getEnabledPlugins = require('../core/loaders/plugins/get-enabled-plugins');
const addSlash = require('../utils/addSlash');
const tsUtils = require('../utils/typescript');
const strapi = require('../index');
module.exports = async function({ browser }) {

View File

@ -90,6 +90,7 @@
"@strapi/plugin-email": "4.1.7",
"@strapi/plugin-upload": "4.1.7",
"@strapi/utils": "4.1.7",
"@strapi/typescript-utils": "4.1.7",
"bcryptjs": "2.4.3",
"boxen": "5.1.2",
"chalk": "4.1.2",

View File

@ -0,0 +1,7 @@
root = true
[*]
end_of_line = lf
insert_final_newline = false
indent_style = space
indent_size = 2

View File

@ -0,0 +1,103 @@
# From https://github.com/Danimoth/gitattributes/blob/master/Web.gitattributes
# Handle line endings automatically for files detected as text
# and leave all files detected as binary untouched.
* text=auto
#
# The above will handle all files NOT found below
#
#
## These files are text and should be normalized (Convert crlf => lf)
#
# source code
*.php text
*.css text
*.sass text
*.scss text
*.less text
*.styl text
*.js text eol=lf
*.coffee text
*.json text
*.htm text
*.html text
*.xml text
*.svg text
*.txt text
*.ini text
*.inc text
*.pl text
*.rb text
*.py text
*.scm text
*.sql text
*.sh text
*.bat text
# templates
*.ejs text
*.hbt text
*.jade text
*.haml text
*.hbs text
*.dot text
*.tmpl text
*.phtml text
# git config
.gitattributes text
.gitignore text
.gitconfig text
# code analysis config
.jshintrc text
.jscsrc text
.jshintignore text
.csslintrc text
# misc config
*.yaml text
*.yml text
.editorconfig text
# build config
*.npmignore text
*.bowerrc text
# Heroku
Procfile text
.slugignore text
# Documentation
*.md text
LICENSE text
AUTHORS text
#
## These files are binary and should be left untouched
#
# (binary is a macro for -text -diff)
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.mov binary
*.mp4 binary
*.mp3 binary
*.flv binary
*.fla binary
*.swf binary
*.gz binary
*.zip binary
*.7z binary
*.ttf binary
*.eot binary
*.woff binary
*.pyc binary
*.pdf binary

View File

@ -0,0 +1,10 @@
# Don't check auto-generated stuff into git
coverage
node_modules
stats.json
package-lock.json
# Cruft
.DS_Store
npm-debug.log
.idea

View File

@ -0,0 +1,25 @@
/**
*
* Initializer
*
*/
import React, { useEffect, useRef } from 'react';
import pluginId from '../../pluginId';
type InitializerProps = {
setPlugin: (id: string) => void;
};
const Initializer: React.FC<InitializerProps> = ({ setPlugin }) => {
const ref = useRef<(id: string) => void | null>(null);
ref.current = setPlugin;
useEffect(() => {
ref.current(pluginId);
}, []);
return null;
};
export default Initializer;

View File

@ -0,0 +1,12 @@
/**
*
* PluginIcon
*
*/
import React from 'react';
import Puzzle from '@strapi/icons/Puzzle';
const PluginIcon: React.VoidFunctionComponent = () => <Puzzle />;
export default PluginIcon;

View File

@ -0,0 +1,66 @@
import React from 'react';
import { prefixPluginTranslations } from '@strapi/helper-plugin';
import pluginPkg from '../../package.json';
import pluginId from './pluginId';
import Initializer from './components/Initializer';
import PluginIcon from './components/PluginIcon';
const name = pluginPkg.strapi.name;
export default {
register(app) {
app.addMenuLink({
to: `/plugins/${pluginId}`,
icon: PluginIcon,
intlLabel: {
id: `${pluginId}.plugin.name`,
defaultMessage: name,
},
Component: async () => {
const component = await import(/* webpackChunkName: "[request]" */ './pages/App');
return component;
},
permissions: [
// Uncomment to set the permissions of the plugin here
// {
// action: '', // the action name should be plugin::plugin-name.actionType
// subject: null,
// },
],
});
const plugin = {
id: pluginId,
initializer: Initializer,
isReady: false,
name,
};
app.registerPlugin(plugin);
},
bootstrap(app) {},
async registerTrads(app) {
const { locales } = app;
const importedTrads = await Promise.all(
locales.map(locale => {
return import(`./translations/${locale}.json`)
.then(({ default: data }) => {
return {
data: prefixPluginTranslations(data, pluginId),
locale,
};
})
.catch(() => {
return {
data: {},
locale,
};
});
})
);
return Promise.resolve(importedTrads);
},
};

View File

@ -0,0 +1,25 @@
/**
*
* This component is the skeleton around the actual pages, and should only
* contain code that should be seen on all pages. (e.g. navigation bar)
*
*/
import React from 'react';
import { Switch, Route } from 'react-router-dom';
import { NotFound } from '@strapi/helper-plugin';
import pluginId from '../../pluginId';
import HomePage from '../HomePage';
const App: React.VoidFunctionComponent = () => {
return (
<div>
<Switch>
<Route path={`/plugins/${pluginId}`} component={HomePage} exact />
<Route component={NotFound} />
</Switch>
</div>
);
};
export default App;

View File

@ -0,0 +1,19 @@
/*
*
* HomePage
*
*/
import React from 'react';
import pluginId from '../../pluginId';
const HomePage: React.VoidFunctionComponent = () => {
return (
<div>
<h1>{pluginId}&apos;s HomePage</h1>
<p>Happy coding</p>
</div>
);
};
export default HomePage;

View File

@ -0,0 +1,5 @@
import pluginPkg from '../../package.json';
const pluginId = pluginPkg.name.replace(/^@strapi\/plugin-/i, '');
export default pluginId;

View File

@ -0,0 +1,40 @@
/**
* axios with a custom config.
*/
import axios from 'axios';
import { auth } from '@strapi/helper-plugin';
const instance = axios.create({
baseURL: process.env.STRAPI_ADMIN_BACKEND_URL,
});
instance.interceptors.request.use(
async (config) => {
config.headers = {
Authorization: `Bearer ${auth.getToken()}`,
Accept: 'application/json',
'Content-Type': 'application/json',
};
return config;
},
(error) => {
Promise.reject(error);
}
);
instance.interceptors.response.use(
(response) => response,
(error) => {
// whatever you want to do with the error
if (error.response?.status === 401) {
auth.clearAppStorage();
window.location.reload();
}
throw error;
}
);
export default instance;

View File

@ -0,0 +1,5 @@
import pluginId from '../pluginId';
const getTrad = (id: string) => `${pluginId}.${id}`;
export default getTrad;

View File

@ -0,0 +1,3 @@
export default ({ strapi }) => {
// bootstrap phase
};

View File

@ -0,0 +1,4 @@
export default {
default: {},
validator() {},
};

View File

@ -0,0 +1 @@
export default {};

View File

@ -0,0 +1,5 @@
import myController from './my-controller';
export default {
myController,
};

View File

@ -0,0 +1,8 @@
export default {
index(ctx) {
ctx.body = strapi
.plugin('{{ pluginName }}')
.service('myService')
.getWelcomeMessage();
},
};

View File

@ -0,0 +1,3 @@
export default ({ strapi }) => {
// destroy phase
};

View File

@ -0,0 +1,23 @@
import register from './register';
import bootstrap from './bootstrap';
import destroy from './destroy';
import config from './config';
import contentTypes from './content-types';
import controllers from './controllers';
import routes from './routes';
import middlewares from './middlewares';
import policies from './policies';
import services from './services/indextjs';
export default {
register,
bootstrap,
destroy,
config,
controllers,
routes,
services,
contentTypes,
policies,
middlewares,
};

View File

@ -0,0 +1 @@
export default {};

View File

@ -0,0 +1 @@
export default {};

View File

@ -0,0 +1,3 @@
export default ({ strapi }) => {
// registeration phase
};

View File

@ -0,0 +1,10 @@
export default [
{
method: 'GET',
path: '/',
handler: 'myController.index',
config: {
policies: [],
},
},
];

View File

@ -0,0 +1,5 @@
import myService from './my-service';
export default {
myService,
};

View File

@ -0,0 +1,5 @@
export default ({ strapi }) => ({
getWelcomeMessage() {
return 'Welcome to Strapi 🚀';
},
});

View File

@ -0,0 +1,3 @@
'use strict';
module.exports = require('./admin/src').default;

View File

@ -0,0 +1,3 @@
'use strict';
module.exports = require('./dist/server');

View File

@ -7,7 +7,7 @@ const nodePlop = require('node-plop');
/**
* Starts the Plop CLI programmatically
*/
const runCLI = () => {
const runCLI = async () => {
Plop.launch({ configPath: join(__dirname, 'plopfile.js') }, env =>
run({ ...env, dest: join(process.cwd(), 'src') }, undefined, true)
);

View File

@ -2,6 +2,8 @@
const { join } = require('path');
const fs = require('fs-extra');
const tsUtils = require('@strapi/typescript-utils');
const validateInput = require('./utils/validate-input');
module.exports = plop => {
@ -46,17 +48,19 @@ module.exports = plop => {
],
actions(answers) {
const filePath = answers.isPluginApi && answers.plugin ? 'plugins/{{plugin}}' : 'api/{{id}}';
const currentDir = process.cwd();
const language = tsUtils.isTypeScriptProjectSync(currentDir) ? 'ts' : 'js';
const baseActions = [
{
type: 'add',
path: `${filePath}/controllers/{{id}}.js`,
templateFile: 'templates/controller.js.hbs',
path: `${filePath}/controllers/{{id}}.${language}`,
templateFile: `templates/${language}/controller.${language}.hbs`,
},
{
type: 'add',
path: `${filePath}/services/{{id}}.js`,
templateFile: 'templates/service.js.hbs',
path: `${filePath}/services/{{id}}.${language}`,
templateFile: `templates/${language}/service.${language}.hbs`,
},
];
@ -67,8 +71,8 @@ module.exports = plop => {
return [
{
type: 'add',
path: `${filePath}/routes/{{id}}.js`,
templateFile: `templates/single-route.js.hbs`,
path: `${filePath}/routes/{{id}}.${language}`,
templateFile: `templates/${language}/single-route.${language}.hbs`,
},
...baseActions,
];

View File

@ -4,6 +4,7 @@ const { join } = require('path');
const slugify = require('@sindresorhus/slugify');
const fs = require('fs-extra');
const { isKebabCase } = require('@strapi/utils');
const tsUtils = require('@strapi/typescript-utils');
const getDestinationPrompts = require('./prompts/get-destination-prompts');
const getFilePath = require('./utils/get-file-path');
@ -81,12 +82,14 @@ module.exports = plop => {
}, {});
const filePath = getFilePath(answers.destination);
const currentDir = process.cwd();
const language = tsUtils.isTypeScriptProjectSync(currentDir) ? 'ts' : 'js';
const baseActions = [
{
type: 'add',
path: `${filePath}/content-types/{{ singularName }}/schema.json`,
templateFile: 'templates/content-type.schema.json.hbs',
templateFile: `templates/${language}/content-type.schema.json.hbs`,
data: {
collectionName: slugify(answers.pluralName, { separator: '_' }),
},
@ -120,20 +123,20 @@ module.exports = plop => {
baseActions.push(
{
type: 'add',
path: `${filePath}/controllers/{{singularName}}.js`,
templateFile: 'templates/core-controller.js.hbs',
path: `${filePath}/controllers/{{singularName}}.${language}`,
templateFile: `templates/${language}/core-controller.${language}.hbs`,
data: { uid },
},
{
type: 'add',
path: `${filePath}/services/{{singularName}}.js`,
templateFile: 'templates/core-service.js.hbs',
path: `${filePath}/services/{{singularName}}.${language}`,
templateFile: `templates/${language}/core-service.${language}.hbs`,
data: { uid },
},
{
type: 'add',
path: `${filePath}/routes/{{singularName}}.js`,
templateFile: `templates/core-router.js.hbs`,
path: `${filePath}/routes/{{singularName}}.${language}`,
templateFile: `templates/${language}/core-router.${language}.hbs`,
data: { uid },
}
);

View File

@ -1,5 +1,7 @@
'use strict';
const tsUtils = require('@strapi/typescript-utils');
const getDestinationPrompts = require('./prompts/get-destination-prompts');
const getFilePath = require('./utils/get-file-path');
const validateInput = require('./utils/validate-input');
@ -19,12 +21,14 @@ module.exports = plop => {
],
actions(answers) {
const filePath = getFilePath(answers.destination);
const currentDir = process.cwd();
const language = tsUtils.isTypeScriptProjectSync(currentDir) ? 'ts' : 'js';
return [
{
type: 'add',
path: `${filePath}/controllers/{{ id }}.js`,
templateFile: 'templates/controller.js.hbs',
path: `${filePath}/controllers/{{ id }}.${language}`,
templateFile: `templates/${language}/controller.${language}.hbs`,
},
];
},

View File

@ -1,5 +1,7 @@
'use strict';
const tsUtils = require('@strapi/typescript-utils');
const getDestinationPrompts = require('./prompts/get-destination-prompts');
const getFilePath = require('./utils/get-file-path');
@ -17,11 +19,14 @@ module.exports = plop => {
],
actions(answers) {
const filePath = getFilePath(answers.destination);
const currentDir = process.cwd();
const language = tsUtils.isTypeScriptProjectSync(currentDir) ? 'ts' : 'js';
return [
{
type: 'add',
path: `${filePath}/middlewares/{{ name }}.js`,
templateFile: 'templates/middleware.js.hbs',
path: `${filePath}/middlewares/{{ name }}.${language}`,
templateFile: `templates/${language}/middleware.${language}.hbs`,
},
];
},

View File

@ -1,6 +1,7 @@
'use strict';
const chalk = require('chalk');
const tsUtils = require('@strapi/typescript-utils');
const logInstructions = pluginName => {
const maxLength = ` resolve: './src/plugins/${pluginName}'`.length;
@ -35,22 +36,27 @@ module.exports = plop => {
},
],
actions(answers) {
const currentDir = process.cwd();
const language = tsUtils.isTypeScriptProjectSync(currentDir) ? 'ts' : 'js';
// TODO: Adds tsconfig & build command for TS plugins?
return [
{
type: 'addMany',
destination: 'plugins/{{ pluginName }}',
base: 'files/plugin',
templateFiles: 'files/plugin/**',
base: `files/${language}/plugin`,
templateFiles: `files/${language}/plugin/**`,
},
{
type: 'add',
path: 'plugins/{{ pluginName }}/README.md',
templateFile: 'templates/README.md.hbs',
templateFile: `templates/${language}/README.md.hbs`,
},
{
type: 'add',
path: 'plugins/{{ pluginName }}/package.json',
templateFile: 'templates/plugin-package.json.hbs',
templateFile: `templates/${language}/plugin-package.json.hbs`,
},
() => plop.renderString(logInstructions(answers.pluginName)),
];

View File

@ -1,5 +1,7 @@
'use strict';
const tsUtils = require('@strapi/typescript-utils');
const getDestinationPrompts = require('./prompts/get-destination-prompts');
const getFilePath = require('./utils/get-file-path');
@ -17,12 +19,14 @@ module.exports = plop => {
],
actions(answers) {
const filePath = getFilePath(answers.destination);
const currentDir = process.cwd();
const language = tsUtils.isTypeScriptProjectSync(currentDir) ? 'ts' : 'js';
return [
{
type: 'add',
path: `${filePath}/policies/{{id}}.js`,
templateFile: 'templates/policy.js.hbs',
path: `${filePath}/policies/{{id}}.${language}`,
templateFile: `templates/${language}/policy.${language}.hbs`,
},
];
},

View File

@ -1,5 +1,7 @@
'use strict';
const tsUtils = require('@strapi/typescript-utils');
const getDestinationPrompts = require('./prompts/get-destination-prompts');
const getFilePath = require('./utils/get-file-path');
@ -17,12 +19,14 @@ module.exports = plop => {
],
actions(answers) {
const filePath = getFilePath(answers.destination);
const currentDir = process.cwd();
const language = tsUtils.isTypeScriptProjectSync(currentDir) ? 'ts' : 'js';
return [
{
type: 'add',
path: `${filePath}/services/{{ id }}.js`,
templateFile: 'templates/service.js.hbs',
path: `${filePath}/services/{{ id }}.${language}`,
templateFile: `templates/${language}/service.${language}.hbs`,
},
];
},

View File

@ -0,0 +1,3 @@
# Strapi plugin {{ pluginName }}
A quick description of {{ pluginName }}.

View File

@ -0,0 +1,49 @@
module.exports = {
routes: [
{
method: 'GET',
path: '/{{pluralize id}}',
handler: '{{id}}.find',
config: {
policies: [],
middlewares: [],
},
},
{
method: 'GET',
path: '/{{pluralize id}}/:id',
handler: '{{id}}.findOne',
config: {
policies: [],
middlewares: [],
},
},
{
method: 'POST',
path: '/{{pluralize id}}',
handler: '{{id}}.create',
config: {
policies: [],
middlewares: [],
},
},
{
method: 'PUT',
path: '/{{pluralize id}}/:id',
handler: '{{id}}.update',
config: {
policies: [],
middlewares: [],
},
},
{
method: 'DELETE',
path: '/{{pluralize id}}/:id',
handler: '{{id}}.delete',
config: {
policies: [],
middlewares: [],
},
},
],
};

View File

@ -0,0 +1,15 @@
{
"kind": "{{kind}}",
"collectionName": "{{ collectionName }}",
"info": {
"singularName": "{{ singularName }}",
"pluralName": "{{ pluralName }}",
"displayName": "{{ displayName }}"
},
"options": {
"draftAndPublish": {{ useDraftAndPublish }},
"comment": ""
},
"attributes": {}
}

View File

@ -0,0 +1,13 @@
/**
* A set of functions called "actions" for `{{id}}`
*/
export default {
// exampleAction: async (ctx, next) => {
// try {
// ctx.body = 'ok';
// } catch (err) {
// ctx.body = err;
// }
// }
};

View File

@ -0,0 +1,7 @@
/**
* {{ id }} controller
*/
import { factories } from '@strapi/strapi'
export default factories.createCoreController('{{ uid }}');

View File

@ -0,0 +1,7 @@
/**
* {{ id }} router.
*/
import { factories } from '@strapi/strapi';
export default factories.createCoreRouter('{{ uid }}');

View File

@ -0,0 +1,7 @@
/**
* {{ id }} service.
*/
import { factories } from '@strapi/strapi';
export default factories.createCoreService('{{ uid }}');

View File

@ -0,0 +1,12 @@
/**
* `{{ name }}` middleware.
*/
export default (config, { strapi }) => {
// Add your own logic here.
return async (ctx, next) => {
strapi.log.info('In {{ name }} middleware.');
await next();
};
};

View File

@ -0,0 +1,24 @@
{
"name": "{{ pluginName }}",
"version": "0.0.0",
"description": "This is the description of the plugin.",
"strapi": {
"name": "{{ pluginName }}",
"description": "Description of {{ pluginName }} plugin",
"kind": "plugin"
},
"dependencies": {},
"author": {
"name": "A Strapi developer"
},
"maintainers": [
{
"name": "A Strapi developer"
}
],
"engines": {
"node": ">=12.x.x <=16.x.x",
"npm": ">=6.0.0"
},
"license": "MIT"
}

View File

@ -0,0 +1,16 @@
/**
* `{{id}}` policy.
*/
export default (policyContext, config, { strapi }) => {
// Add your own logic here.
strapi.log.info('In {{id}} policy.');
const canDoSomething = true;
if (canDoSomething) {
return true;
}
return false;
};

View File

@ -0,0 +1,5 @@
/**
* {{id}} service.
*/
eexport default () => ({});

View File

@ -0,0 +1,13 @@
export default {
routes: [
// {
// method: 'GET',
// path: '/{{id}}',
// handler: '{{id}}.exampleAction',
// config: {
// policies: [],
// middlewares: [],
// },
// },
],
};

View File

@ -0,0 +1,31 @@
export default {
routes: [
{
method: 'GET',
path: '/{{id}}',
handler: '{{id}}.find',
config: {
policies: [],
middlewares: [],
},
},
{
method: 'PUT',
path: '/{{id}}',
handler: '{{id}}.update',
config: {
policies: [],
middlewares: [],
},
},
{
method: 'DELETE',
path: '/{{id}}',
handler: '{{id}}.delete',
config: {
policies: [],
middlewares: [],
},
},
],
};

View File

@ -29,6 +29,7 @@
],
"main": "lib/index.js",
"dependencies": {
"@strapi/typescript-utils": "4.1.1",
"@sindresorhus/slugify": "1.1.0",
"@strapi/utils": "4.1.7",
"chalk": "4.1.2",

View File

@ -0,0 +1,22 @@
Copyright (c) 2015-present Strapi Solutions SAS
Portions of the Strapi software are licensed as follows:
* All software that resides under an "ee/" directory (the “EE Software”), if that directory exists, is licensed under the license defined in "ee/LICENSE".
* All software outside of the above-mentioned directories or restrictions above is available under the "MIT Expat" license as set forth below.
MIT Expat License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,10 +1,11 @@
'use strict';
const compilers = require('./compilers');
const getConfigPath = require('./get-config-path');
const copyResources = require('./copy-resources');
const getConfigPath = require('./utils/get-config-path');
const copyResources = require('./utils/copy-resources');
module.exports = async (srcDir, { watch = false }) => {
// TODO: Use the Strapi debug logger instead or don't log at all
console.log(`Starting the compilation for TypeScript files in ${srcDir}`);
const compiler = watch ? compilers.watch : compilers.basic;

View File

@ -2,8 +2,8 @@
const ts = require('typescript');
const reportDiagnostics = require('../report-diagnostics');
const resolveConfigOptions = require('../resolve-config-options');
const reportDiagnostics = require('../utils/report-diagnostics');
const resolveConfigOptions = require('../utils/resolve-config-options');
module.exports = {
/**

Some files were not shown because too many files have changed in this diff Show More