UNPKG

create-strapi-app

Version:

Generate a new Strapi application.

181 lines (175 loc) • 6.26 kB
'use strict'; var path = require('node:path'); var url = require('node:url'); var node_stream = require('node:stream'); var promises = require('node:stream/promises'); var tar = require('tar'); var retry = require('async-retry'); var fse = require('fs-extra'); function _interopNamespaceDefault(e) { var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var tar__namespace = /*#__PURE__*/_interopNamespaceDefault(tar); const stripTrailingSlash = (str)=>{ return str.endsWith('/') ? str.slice(0, -1) : str; }; // Merge template with new project being created async function copyTemplate(scope, rootPath) { const { template } = scope; if (!template) { throw new Error('Missing template or example app option'); } if (await isOfficialTemplate(template, scope.templateBranch)) { await retry(()=>downloadGithubRepo(rootPath, { owner: 'strapi', repo: 'strapi', branch: scope.templateBranch, subPath: `templates/${template}` }), { retries: 3, onRetry (err, attempt) { console.log(`Retrying to download the template. Attempt ${attempt}. Error: ${err}`); } }); return; } if (isLocalTemplate(template)) { const filePath = template.startsWith('file://') ? url.fileURLToPath(template) : template; await fse.copy(filePath, rootPath); } if (isGithubShorthand(template)) { const [owner, repo, ...pathSegments] = template.split('/'); const subPath = pathSegments.length ? pathSegments.join('/') : scope.templatePath; await retry(()=>downloadGithubRepo(rootPath, { owner, repo, branch: scope.templateBranch, subPath }), { retries: 3, onRetry (err, attempt) { console.log(`Retrying to download the template. Attempt ${attempt}. Error: ${err}`); } }); return; } if (isGithubRepo(template)) { const url = new URL(template); const [owner, repo, t, branch, ...pathSegments] = stripTrailingSlash(url.pathname.slice(1)).split('/'); if (t !== undefined && t !== 'tree') { throw new Error(`Invalid GitHub template URL: ${template}`); } if (scope.templateBranch) { await retry(()=>downloadGithubRepo(rootPath, { owner, repo, branch: scope.templateBranch, subPath: scope.templatePath }), { retries: 3, onRetry (err, attempt) { console.log(`Retrying to download the template. Attempt ${attempt}. Error: ${err}`); } }); return; } await retry(()=>downloadGithubRepo(rootPath, { owner, repo, branch: decodeURIComponent(branch) ?? scope.templateBranch, subPath: pathSegments.length ? decodeURIComponent(pathSegments.join('/')) : scope.templatePath }), { retries: 3, onRetry (err, attempt) { console.log(`Retrying to download the template. Attempt ${attempt}. Error: ${err}`); } }); throw new Error(`Invalid GitHub template URL: ${template}`); } } async function downloadGithubRepo(rootPath, { owner, repo, branch, subPath }) { const filePath = subPath ? subPath.split('/').join(path.posix.sep) : null; let checkContentUrl = `https://api.github.com/repos/${owner}/${repo}/contents`; if (filePath) { checkContentUrl = `${checkContentUrl}/${filePath}`; } if (branch) { checkContentUrl = `${checkContentUrl}?ref=${branch}`; } const checkRes = await fetch(checkContentUrl, { method: 'HEAD' }); if (checkRes.status !== 200) { throw new Error(`Could not find a template at https://github.com/${owner}/${repo}${branch ? ` on branch ${branch}` : ''}${filePath ? ` at path ${filePath}` : ''}`); } let url = `https://api.github.com/repos/${owner}/${repo}/tarball`; if (branch) { url = `${url}/${branch}`; } const res = await fetch(url); if (!res.body) { throw new Error(`Failed to download ${url}`); } await promises.pipeline(// @ts-expect-error - Readable is not a valid source node_stream.Readable.fromWeb(res.body), tar__namespace.x({ cwd: rootPath, strip: filePath ? filePath.split('/').length + 1 : 1, filter (path) { if (filePath) { return path.split('/').slice(1).join('/').startsWith(filePath); } return true; } })); } function isLocalTemplate(template) { return template.startsWith('file://') || fse.existsSync(path.isAbsolute(template) ? template : path.resolve(process.cwd(), template)); } function isGithubShorthand(value) { if (isValidUrl(value)) { return false; } return /^[\w-]+\/[\w-.]+(\/[\w-.]+)*$/.test(value); } function isGithubRepo(value) { try { const url = new URL(value); return url.origin === 'https://github.com'; } catch { return false; } } function isValidUrl(value) { try { // eslint-disable-next-line no-new new URL(value); return true; } catch { return false; } } const OFFICIAL_NAME_REGEX = /^[a-zA-Z]*$/; async function isOfficialTemplate(template, branch) { if (isValidUrl(template) || !OFFICIAL_NAME_REGEX.test(template)) { return false; } const res = await fetch(`https://api.github.com/repos/strapi/strapi/contents/templates/${template}?${branch ? `ref=${branch}` : ''}`, { method: 'HEAD' }); return res.status === 200; } exports.copyTemplate = copyTemplate; //# sourceMappingURL=template.js.map