-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit f33e43a
Showing
22 changed files
with
7,446 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
module.exports = { | ||
extends: ['@salutejs/eslint-config'], | ||
ignorePatterns: ['*.d.ts', 'coverage/*', 'build/*'], | ||
rules: { | ||
'react/react-in-jsx-scope': 'off', | ||
'@typescript-eslint/explicit-module-boundary-types': 'off', | ||
'no-console': ['warn', { allow: ['warn', 'error'] }], | ||
}, | ||
overrides: [ | ||
{ | ||
files: ['*.mjs'], | ||
rules: { | ||
'no-console': 'off', | ||
}, | ||
}, | ||
], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
node_modules | ||
template-app | ||
.template-package |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
save-exact=true | ||
@salutejs:registry=https://registry.npmjs.org/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
module.exports = { | ||
"parser": "typescript", | ||
"arrowParens": "always", | ||
"printWidth": 120, | ||
"endOfLine": "auto", | ||
"semi": true, | ||
"singleQuote": true, | ||
"tabWidth": 4, | ||
"trailingComma": "all" | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# @salutejs/cerate-app | ||
Шаблонизатор проектов | ||
|
||
Простейший способ получить заготовку проекта это выполнить команду | ||
|
||
|
||
```bash | ||
npx @salutejs/cerate-app | ||
``` | ||
|
||
После запуска появится визард, в котором можно указать имя проекта и прочие опции. После завершения работы скрипта в текущей рабоче директории терминала будет создана еще одна директория с именем указанным как имя проекта. | ||
|
||
|
||
### Параметр `--templatePackage` | ||
При запуске команды без аргументов будет выбран пакет `@salutejs/canvas-example` как пакет-шаблон. Но можно указать в качестве шаблона любой другой пакет. При отсутствии дополнительной конфигурации пакет-шаблон будет просто скопирован в целевую папку. | ||
|
||
```bash | ||
npx @salutejs/cerate-app --templatePackage any-npm-package | ||
``` | ||
|
||
Если ваш пакет требует авторизации в npm, можно задать токен доступа в env-переменную `NPM_REGISTRY_TOKEN`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#!/usr/bin/env bash | ||
|
||
SELF_PATH=$0 | ||
LINK_PATH=$(readlink $SELF_PATH) | ||
LINK_DIR=$(dirname -- $LINK_PATH) | ||
PACKAGE_DIR=$(dirname -- $SELF_PATH)/$LINK_DIR | ||
RUN_DIR=$(pwd) | ||
|
||
node --experimental-import-meta-resolve $PACKAGE_DIR/src/cliWizard.mjs $@ --runDir $RUN_DIR |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
{ | ||
"name": "@salutejs/create-app", | ||
"version": "0.1.7", | ||
"scripts": { | ||
"build": "echo no build needed", | ||
"test": "jest --testTimeout=30000", | ||
"lint": "eslint --ext .js,.mjs ./src", | ||
"start": "bash index.sh" | ||
}, | ||
"dependencies": { | ||
"chalk": "5.0.0", | ||
"gulp-if": "3.0.0", | ||
"hpagent": "1.0.0", | ||
"inquirer": "8.2.0", | ||
"lodash": "4.17.21", | ||
"micromatch": "4.0.4", | ||
"mustache": "4.2.0", | ||
"node-fetch": "3.2.4", | ||
"through2": "4.0.2", | ||
"vinyl-fs": "3.0.3", | ||
"yargs": "17.3.1" | ||
}, | ||
"devDependencies": { | ||
"@salutejs/eslint-config": "0.4.0", | ||
"@typescript-eslint/eslint-plugin": "2.29.0", | ||
"@typescript-eslint/parser": "2.29.0", | ||
"babel-eslint": "10.1.0", | ||
"concat-stream": "2.0.0", | ||
"eslint": "6.8.0", | ||
"eslint-config-airbnb": "18.1.0", | ||
"eslint-config-prettier": "6.11.0", | ||
"eslint-config-react-app": "5.2.1", | ||
"eslint-plugin-cypress": "2.11.1", | ||
"eslint-plugin-flowtype": "4.7.0", | ||
"eslint-plugin-import": "2.22.1", | ||
"eslint-plugin-jest": "23.8.2", | ||
"eslint-plugin-jsx-a11y": "6.2.3", | ||
"eslint-plugin-no-only-tests": "2.4.0", | ||
"eslint-plugin-prettier": "3.1.3", | ||
"eslint-plugin-react": "7.19.0", | ||
"eslint-plugin-react-hooks": "3.0.0", | ||
"eslint-plugin-react-perf": "3.3.0", | ||
"eslint-plugin-vue": "6.2.2", | ||
"jest": "27.5.1", | ||
"prettier": "2.0.5", | ||
"typescript": "3.8.3" | ||
}, | ||
"main": "./src/cliWizard.mjs", | ||
"files": [ | ||
"src/**/*" | ||
], | ||
"bin": "./index.sh", | ||
"publishConfig": { | ||
"access": "public" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
"\n\u001b[32m░█▀▀░█▀█░█░░░█░█░▀█▀░█▀▀░▀▀█░█▀▀░░░█░█▀▀░█▀▄░█▀▀░█▀█░▀█▀░█▀▀░░░░░█▀█░█▀█░█▀█\u001b[39m\n\u001b[32m░▀▀█░█▀█░█░░░█░█░░█░░█▀▀░░░█░▀▀█░▄▀░░█░░░█▀▄░█▀▀░█▀█░░█░░█▀▀░▄▄▄░█▀█░█▀▀░█▀▀\u001b[39m\n\u001b[32m░▀▀▀░▀░▀░▀▀▀░▀▀▀░░▀░░▀▀▀░▀▀░░▀▀▀░▀░░░▀▀▀░▀░▀░▀▀▀░▀░▀░░▀░░▀▀▀░░░░░▀░▀░▀░░░▀░░\u001b[39m\n" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import fs from 'fs'; | ||
import vinylFs from 'vinyl-fs'; | ||
import gulpIf from 'gulp-if'; | ||
import micromatch from 'micromatch'; | ||
|
||
import { mustachePlugin } from './gulpPlugins/mustachePlugin.mjs'; | ||
import { buildJsonPlugin } from './gulpPlugins/buildJsonPlugin.mjs'; | ||
import { renamePlugin } from './gulpPlugins/renamePlugin.mjs'; | ||
|
||
const { src, dest } = vinylFs; | ||
|
||
function buildTemplate(srcGlob, destFolder, config, rules) { | ||
let stream = src(srcGlob, { nodir: true, dot: true }) | ||
.pipe( | ||
renamePlugin((file) => { | ||
const entry = config.rename.find((renameEntry) => micromatch.isMatch(file.path, renameEntry.glob)); | ||
|
||
if (entry) { | ||
entry.map(file); | ||
} | ||
}), | ||
) | ||
.pipe( | ||
renamePlugin((file) => { | ||
if (file.extname === '.mustache') { | ||
file.extname = ''; | ||
} | ||
}), | ||
); | ||
|
||
for (const rule of rules) { | ||
stream = stream.pipe(gulpIf(rule.test, mustachePlugin(config.featureToggles, rule.tags))); | ||
} | ||
|
||
return stream.pipe(buildJsonPlugin(config)).pipe(dest(destFolder)); | ||
} | ||
|
||
export const buildTemplateTask = async (config, rules) => { | ||
const taskPromises = []; | ||
|
||
Object.values(config.paths).map(({ source, destination }) => { | ||
let resolve; | ||
let reject; | ||
|
||
const taskFinished = new Promise((res, rej) => { | ||
resolve = res; | ||
reject = rej; | ||
}); | ||
|
||
taskPromises.push(taskFinished); | ||
|
||
fs.rmdirSync(destination, { recursive: true }); | ||
|
||
return buildTemplate(source, destination, config, rules) | ||
.on('end', () => { | ||
resolve(); | ||
}) | ||
.on('error', (err) => { | ||
reject(err); | ||
}); | ||
}); | ||
|
||
await Promise.all(taskPromises); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
import inquirer from 'inquirer'; | ||
import path from 'path'; | ||
import chalk from 'chalk'; | ||
import { execSync } from 'child_process'; | ||
import { existsSync } from 'fs'; | ||
|
||
import { cleanUp, downloadTemplatePackage, extractTemplatePackage, getArgv, printLogo } from './utils.mjs'; | ||
import { buildTemplateTask } from './buildTemplate.mjs'; | ||
import { getConfigFromAnswers } from './config.mjs'; | ||
import { defaultRules } from './defaults/rules.mjs'; | ||
|
||
const CONFIG_ENTRY_POINT = '.create-app/index.mjs'; | ||
const DEFAULT_TEMPLATE = '@salutejs/canvas-example'; | ||
|
||
const checkboxInstructionsTranslation = `\n (Нажмите ${chalk.bold( | ||
chalk.cyan('<space>'), | ||
)} чтобы переключить функцию, ${chalk.bold(chalk.cyan('<enter>'))} чтобы завершить выбор)\n`; | ||
|
||
export async function run() { | ||
try { | ||
const { | ||
templatePath, | ||
output, | ||
runDir, | ||
configPath = CONFIG_ENTRY_POINT, | ||
templatePackage = DEFAULT_TEMPLATE, | ||
} = getArgv(); | ||
|
||
printLogo(); | ||
|
||
let resolvedTemplatePath; | ||
|
||
if (templatePath) { | ||
resolvedTemplatePath = path.resolve(templatePath); | ||
} else { | ||
const packageBuffer = await downloadTemplatePackage(templatePackage); | ||
resolvedTemplatePath = extractTemplatePackage(packageBuffer); | ||
} | ||
|
||
const templateConfig = existsSync(`${resolvedTemplatePath}/${configPath}`) | ||
? `${resolvedTemplatePath}/${configPath}` | ||
: configPath; | ||
|
||
const templateModule = existsSync(templateConfig) ? await import(templateConfig) : {}; | ||
const { featureToggles = [], featureConfigMap = {}, templateDescription = '', rules = [] } = templateModule; | ||
|
||
if (templateDescription) { | ||
console.log(`${chalk.bold('Описание шаблона:')} ${templateDescription}`); | ||
console.log(''); | ||
} | ||
|
||
const featureChoices = featureToggles | ||
.filter((toggle) => !toggle.hidden) | ||
.map((toggle) => { | ||
return { | ||
name: toggle.name, | ||
checked: toggle.defaultValue, | ||
value: toggle.featureId, | ||
short: toggle.featureId, | ||
}; | ||
}); | ||
|
||
const questions = [ | ||
{ | ||
type: 'input', | ||
name: 'projectName', | ||
message: 'Название вашего проекта:', | ||
default: 'template-app', | ||
}, | ||
{ | ||
type: 'confirm', | ||
name: 'changeDefaults', | ||
message: 'Хотите изменить список стандартных функций проекта?', | ||
default: false, | ||
when: featureChoices.length !== 0 && Object.keys(featureConfigMap).length !== 0, | ||
}, | ||
{ | ||
type: 'checkbox', | ||
name: 'featureIds', | ||
message: 'Измените список стандартных функций', | ||
suffix: checkboxInstructionsTranslation, | ||
loop: false, | ||
choices: featureChoices, | ||
pageSize: 12, | ||
when: (answers) => answers.changeDefaults, | ||
}, | ||
{ | ||
type: 'confirm', | ||
name: 'installDependencies', | ||
message: 'Выполнить установку зависимостей (npm install)?', | ||
default: true, | ||
}, | ||
]; | ||
|
||
const answers = await inquirer.prompt(questions); | ||
|
||
const defaultFeatureToggles = featureToggles | ||
.filter((toggle) => toggle.hidden && toggle.defaultValue) | ||
.map((toggle) => toggle.featureId); | ||
|
||
const featureIds = answers.featureIds | ||
? answers.featureIds | ||
: featureToggles.filter((toggle) => toggle.defaultValue).map((toggle) => toggle.featureId); | ||
|
||
const withHiddenToggles = { | ||
...answers, | ||
featureIds: [...new Set([...featureIds, ...defaultFeatureToggles])], // оставляем уникальное объединение | ||
}; | ||
|
||
const destination = output || `${runDir}/${answers.projectName}`; | ||
const config = getConfigFromAnswers({ | ||
answers: withHiddenToggles, | ||
featureConfigMap, | ||
templatePath: `${resolvedTemplatePath}/`, | ||
output: destination, | ||
runDir, | ||
}); | ||
|
||
await buildTemplateTask(config, [...defaultRules, rules]); | ||
|
||
if (answers.installDependencies) { | ||
console.log(''); | ||
console.log('Установка зависимостей'); | ||
console.log(''); | ||
execSync('npm i', { | ||
cwd: destination, | ||
encoding: 'UTF-8', | ||
stdio: 'inherit', | ||
}); | ||
console.log(''); | ||
console.log('Установка зависимостей завершена'); | ||
} | ||
|
||
console.log(''); | ||
console.log(chalk.green('✅ Готово!')); | ||
console.log(''); | ||
} catch (err) { | ||
console.error(err); | ||
} finally { | ||
cleanUp(); | ||
} | ||
} | ||
|
||
run(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
export function getConfigFromAnswers({ answers, featureConfigMap, templatePath, output, runDir }) { | ||
const enabledFeatureIds = Object.entries(featureConfigMap) | ||
.filter(([, feature]) => feature.test(answers.featureIds)) | ||
.map(([key]) => key); | ||
|
||
const defaultFeatureToggles = Object.fromEntries(Object.keys(featureConfigMap).map((key) => [key, false])); | ||
const featureToggles = [...enabledFeatureIds, ...answers.featureIds].reduce((acc, id) => { | ||
acc[id] = true; | ||
|
||
return acc; | ||
}, {}); | ||
|
||
const configDiff = Object.keys(defaultFeatureToggles).reduce( | ||
(acc, featureId) => { | ||
const state = enabledFeatureIds.includes(featureId) ? 'on' : 'off'; | ||
const featureConfig = featureConfigMap[featureId].config({ templatePath }); | ||
|
||
acc.jsonChanges.push(...(featureConfig[state].jsonChanges || [])); | ||
acc.sourceAddons.push(...(featureConfig[state].sourceAddon || [])); | ||
acc.rename.push(...(featureConfig[state].rename || [])); | ||
|
||
return acc; | ||
}, | ||
{ | ||
jsonChanges: [], | ||
sourceAddons: [], | ||
rename: [], | ||
}, | ||
); | ||
|
||
return { | ||
featureToggles: { | ||
...defaultFeatureToggles, | ||
...featureToggles, | ||
}, | ||
paths: { | ||
default: { | ||
source: [ | ||
`${templatePath}**/*`, | ||
`!${templatePath}node_modules/**`, | ||
`!${templatePath}build/**`, | ||
`!${templatePath}.next/**`, | ||
...configDiff.sourceAddons, | ||
], | ||
destination: output || `${runDir}/${answers.projectName}`, | ||
}, | ||
}, | ||
rename: configDiff.rename, | ||
jsonChanges: [ | ||
{ | ||
glob: `${templatePath}package.json`, | ||
changes: { | ||
merge: { | ||
name: answers.projectName, | ||
}, | ||
}, | ||
}, | ||
...configDiff.jsonChanges, | ||
], | ||
}; | ||
} |
Oops, something went wrong.