diff --git a/CHANGELOG.md b/CHANGELOG.md index d4db92c..dd50f37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,26 @@ _Note: Gaps between patch versions are faulty, broken or test releases._ +## v2.0.0 (2023-08-10) + +#### :boom: [Breaking Change] + +* `make-test` - the command interface has been changed +* `make` - support for the `make app` has been removed + +#### :rocket: [New Feature] + +* `create-app` - the function has been added for the easy creation of v4fire app + +#### :house: Internal + +* Moved to using Handlebars templates + +#### :memo: [Documentation] + +* `help` - documentation has been updated +* README.md has been updated + ## v1.5.2 (2023-04-14) #### :bug: Bug Fix diff --git a/README.md b/README.md index 3ef21ae..c60384f 100644 --- a/README.md +++ b/README.md @@ -8,15 +8,20 @@ v4fire -h ## Usage -### Make app +### Create app It is the easiest way to start use V4Fire ```bash -v4fire make app my-app && cd my-app && npm run build +v4fire create-app my-app && yarn build ``` -It will create application ready for work. +It will create application ready for work in the current directory. + +```bash +v4fire create-app my-app/foo/bar && cd my-app/foo/bar && yarn build +``` +It will create application ready for work in the target directory. ### Create a workspace @@ -45,13 +50,13 @@ It will remove workspace folder, clear package-lock.json and components-lock.jso v4fire make block hello-world ``` -It will create `src/base/b-hello-world` component. +It will create `src/components/b-hello-world` component. ```bash v4fire make block b-hello-world ``` -Also, it will create `src/base/b-hello-world`. +Also, it will create `src/components/b-hello-world`. ```bash v4fire make page hello-world @@ -84,7 +89,7 @@ v4fire make block hello-world --template functional --extend i-data v4fire rename hello-world app-loader ``` -It will rename `src/base/b-hello-world` to `src/base/b-app-loader`. +It will rename `src/components/b-hello-world` to `src/components/b-app-loader`. ### Resolve changelog @@ -98,18 +103,28 @@ WARNING: Conflicts within the same record may not be resolved correctly! ### Make test ```bash -v4fire make-test src/base/b-slider +v4fire make-test block hello-world ``` +It will generate simple tests for the `src/components/**/b-hello-world` component, if it exists. -You can generate test files for both component and module. -The tool also will take care of updating [demo-page](https://github.com/V4Fire/Client/blob/master/src/pages/p-v4-components-demo/index.js) -dependencies and adding new test cases to [test cases file](https://github.com/V4Fire/Client/blob/master/tests/cases.js). +```bash +v4fire make-test page slider +``` +It will generate simple tests for the `src/pages/**/p-slider` page, if it exists. -For both component and module the tool generates `test/index.js` [file](src/templates/test/module/simple/index.js) -that performs basic test setup and executes simple test. +```bash +v4fire make-test block src/foo/bar/componentName +``` +It will generate simple `component` tests in the `src/foo/bar/componentName` folder + +```bash +v4fire make-test page src/foo/bar/componentName +``` +It will generate simple `page` tests in the `src/foo/bar/componentName` folder + +The tool also will take care of updating [demo-page](https://github.com/V4Fire/Client/blob/master/src/pages/p-v4-components-demo/index.js) -In case of _module_ test, the tool relies on `b-dummy` [component](https://github.com/V4Fire/Client/tree/master/src/base/b-dummy) -designed specifically for testing purposes. +The tool generates a `test` folder for both components and pages. The [template for component](src/templates/test/block) and the [template for page](src/templates/test/block) contain the basic test setup and can execute these simple tests. #### Runners @@ -118,7 +133,7 @@ and all test code locates in the `test/index.js` file. So if you'd like to have you can specify them just after the path to module or component being tested. ```bash -v4fire make-test src/base/b-slider analytics render events +v4fire make-test src/components/b-slider analytics render events ``` For each specified runner the tool will create `test/runner/runner-name` file. [Here is the example](src/templates/test/module/with-runners/runners/runner.js) diff --git a/bin/cli.js b/bin/cli.js index 2612184..5c9067e 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -13,15 +13,25 @@ const {Application} = require('../src/application'); const options = yargs .command( - 'make-test [runners..]', - 'Make test for module or component', + 'create-app [target]', + 'Make simple application using basic v4fire template', + (yargs) => { + yargs.positional('target', { + type: 'string' + }); + } + ) + .command( + 'make-test ', + 'Make test for page or component', (yargs) => { yargs - .positional('path', { - demandOption: true, - type: 'string' + .positional('subject', { + type: 'string', + choices: ['page', 'block'] }) - .positional('runners', { + .positional('target', { + demandOption: true, type: 'string' }); } @@ -67,13 +77,13 @@ const options = yargs .command( 'make [path]', - 'Make block, page or app', + 'Make block or page', (yargs) => { yargs .positional('subject', { default: 'block', type: 'string', - choices: ['block', 'page', 'app'] + choices: ['block', 'page'] }) .positional('name', { demandOption: true, @@ -148,16 +158,12 @@ const options = yargs .example('v4fire make block point', 'Make i-block b-point') .example('v4fire make page card', 'Make i-dynamic-page p-card') .example( - 'v4fire make-test src/core/view-history', - 'Make tests for view-history module' - ) - .example( - 'v4fire make-test src/base/b-slider', - 'Make tests for b-slider component' + 'v4fire make-test block slider', + 'Make tests for src/components/**/b-slider component, if it exists' ) .example( - 'v4fire make-test src/base/b-slider analytics render events', - 'Make tests for b-slider component with different runners' + 'v4fire make-test page src/foo/bar/p-test', + 'Make tests for src/foo/bar/p-test page' ) .example( 'v4fire resolve-changelog', diff --git a/package.json b/package.json index 2f89f24..682c5b4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@v4fire/cli", - "version": "1.6.0", + "version": "2.0.0", "description": "Tools for creating V4Fire blocks and pages from CLI", "main": "index.js", "bin": { @@ -27,6 +27,7 @@ "fs-extra": "11.1.1", "git-config-path": "2.0.0", "glob": "9.3.4", + "handlebars": "4.7.7", "parse-git-config": "3.0.0", "typescript": "4.4.4", "yargs": "17.7.1" diff --git a/src/application.js b/src/application.js index 7c90194..7310397 100644 --- a/src/application.js +++ b/src/application.js @@ -29,18 +29,18 @@ class Application { async run() { try { - const {command, subject} = this.config; + const + {commandNative: command, subject} = this.config; - this.log.info(`Command:${command} ${subject}`); + this.log.info(`Command: ${command} ${subject}`); - const controller = - this.getControllerInstance( + const controller = this.getControllerInstance( `${ucfirst(camelize(`${command}-${subject}`))}Controller` ) || this.getControllerInstance(`${ucfirst(camelize(command))}Controller`); if (controller == null) { - throw new Error(`Unknown controller: ${controllerName}`); + throw new Error('Unknown controller'); } await controller.run(); diff --git a/src/controllers/create-app.js b/src/controllers/create-app.js new file mode 100644 index 0000000..cef9b51 --- /dev/null +++ b/src/controllers/create-app.js @@ -0,0 +1,30 @@ +const path = require('path'); +const {Controller} = require('../core/controller'); + +class CreateAppController extends Controller { + /** @override */ + async run() { + const + source = this.vfs.resolve(__dirname, '../templates/app'), + appName = this.config.target || 'v4fire-app', + appPath = appName.split(path.sep), + directoryExists = this.vfs.exists(this.config.target) && this.vfs.isDirectory(this.config.target); + + let + destination = './'; + + if (appPath.length <= 1 && !directoryExists) { + this.vfs.resolve('./'); + + } else { + destination = this.vfs.resolve(...appPath); + } + + this.handlebarsOptions = {name: appName}; + + await this.vfs.ensureDir(destination); + await this.copyDir(source, destination, {withFolders: true}); + } +} + +module.exports = CreateAppController; diff --git a/src/controllers/index.js b/src/controllers/index.js index edddedf..cb45a4e 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -5,6 +5,7 @@ const ResolveChangelogController = require('./resolve-changelog'); const CreateWorkspaceController = require('./create-workspace'); const RemoveWorkspaceController = require('./remove-workspace'); const UpGitController = require('./up-yarn-git-dependencies'); +const CreateAppController = require('./create-app'); module.exports = { MakeController, @@ -13,5 +14,6 @@ module.exports = { ResolveChangelogController, CreateWorkspaceController, UpGitController, - RemoveWorkspaceController + RemoveWorkspaceController, + CreateAppController }; diff --git a/src/controllers/make-test.js b/src/controllers/make-test.js index 1367289..0d16f65 100644 --- a/src/controllers/make-test.js +++ b/src/controllers/make-test.js @@ -3,7 +3,6 @@ const ts = require('typescript'); const {Controller} = require('../core/controller'); const {AbstractSyntaxTree} = require('../core/ast'); -const {camelize, ucfirst} = require('../core/helpers'); class MakeTestController extends Controller { /** @@ -11,14 +10,8 @@ class MakeTestController extends Controller { */ ast; - /** - * Default name of component for module testing - * @type {string} - */ - defaultComponentName = 'b-dummy'; - + /** @override */ async run() { - this.updateCases(this.config.runners); this.updateDemoPageDeps(); const source = this.vfs.resolve( @@ -26,154 +19,30 @@ class MakeTestController extends Controller { '..', 'templates', 'test', - this.component === this.moduleOrComponentName ? 'component' : 'module', - this.config.runners.length === 0 ? 'simple' : 'with-runners' + this.config.subject ); - const destination = this.vfs.resolve(this.config.path, 'test'); + const + name = this.resolveName(this.config.target, this.prefix), + clearName = this.resolveName(this.config.target, this.prefix, false); - await this.copyTestFolder(source, destination); - } + let + destination = this.config.target; - /** - * Name of component tests being generated for - * @returns {string} - */ - get component() { - const dirName = this.config.path.split(path.sep).pop(); + if (destination.split(path.sep).length === 1) { + const + chunk = this.config.subject === 'page' ? 'pages' : 'components', + globPattern = `${this.vfs.resolve('src', chunk)}/**/${name}`; - if (/^b-/.test(dirName)) { - return dirName; + destination = this.vfs.getFilesByGlobPattern(globPattern)[0]; } - return this.defaultComponentName; - } + this.handlebarsOptions = {name, clearName}; - /** - * Name of component or module for generating tests - * @returns {string} - */ - get moduleOrComponentName() { - if (this.component !== this.defaultComponentName) { - return this.component; - } + destination = this.vfs.resolve(destination, 'test'); + await this.vfs.ensureDir(destination, 'test'); - return this.config.path.split(path.sep).pop(); - } - - /** - * Copies test folder from source to destination with replacing component/module names - * - * @param source - * @param destination - * - * @returns {Promise} - */ - async copyTestFolder(source, destination) { - await this.vfs.ensureDir(destination); - - const defName = - this.moduleOrComponentName === this.component ? 'b-name' : 'name'; - - const indexFileSource = this.vfs.resolve(source, 'index.js'), - indexFileDestination = this.vfs.resolve(destination, 'index.js'), - indexFileData = this.vfs.readFile(indexFileSource); - - this.vfs.writeFile( - indexFileDestination, - this.replaceNames(indexFileData, this.moduleOrComponentName, defName) - ); - - this.log.msg(`New file: ${indexFileDestination}`); - - const {runners} = this.config; - - if (runners.length === 0) { - return; - } - - const runnersSource = this.vfs.resolve(source, 'runners', 'runner.js'), - runnersDestination = this.vfs.resolve(destination, 'runners'), - runnerData = this.vfs.readFile(runnersSource); - - await this.vfs.ensureDir(runnersDestination); - - runners.forEach((runner) => { - const runnerFileDestination = this.vfs.resolve( - runnersDestination, - `${runner}.js` - ); - - this.vfs.writeFile( - runnerFileDestination, - this.replaceNames( - runnerData, - this.moduleOrComponentName, - defName, - runner - ) - ); - - this.log.msg(`New file: ${runnerFileDestination}`); - }); - } - - /** - * Updates `cases.js` by adding new cases for generated tests - * @param {string[]} runners - */ - updateCases(runners) { - const sourcePath = this.vfs.resolve('tests/cases.js'); - - if (!this.vfs.exists(sourcePath)) { - this.log.error( - `File ${sourcePath} does not exist.\nCreate it and write a basic structure of it in order to generate cases.` - ); - - return; - } - - const source = this.ast.createSourceFile(sourcePath); - - const commentString = `// ${this.moduleOrComponentName}`, - testEntryPath = this.vfs.pathByRoot( - this.vfs.resolve(this.config.path, 'test') - ); - - const caseStrings = []; - - if (runners.length === 0) { - caseStrings.push( - `\n\t'--test-entry ${this.vfs.removeTrailingSep(testEntryPath)}'` - ); - } else { - runners.forEach((runner) => { - caseStrings.push( - `\n\t'--test-entry ${this.vfs.removeTrailingSep( - testEntryPath - )} --runner ${runner}'` - ); - }); - } - - const casesNodeObject = this.ast.findASTNodeObject( - source, - (node) => ts.SyntaxKind[node.kind] === 'ArrayLiteralExpression' - ), - cases = casesNodeObject.elements, - insertPosition = cases.end; - - const sourceFile = this.vfs.readFile(sourcePath); - - const newFile = `${sourceFile.slice( - 0, - insertPosition - )},\n\n\t${commentString}${caseStrings.join(',')}${sourceFile.slice( - insertPosition - )}`; - - this.vfs.writeFile(sourcePath, newFile); - this.log.msg(`Update file: ${sourcePath}`); + await this.copyDir(source, destination, {withFolders: true}); } /** @@ -250,32 +119,6 @@ class MakeTestController extends Controller { this.log.msg(`Update file: ${sourcePath}`); } - /** - * Replaces all occurrences of `defName` with `newName` with different typings - * - * @param {string} content - * @param {string} newName - * @param {string} defName - * @param {string | undefined} runner - * - * @returns {string} - */ - replaceNames(content, newName, defName = 'b-name', runner = undefined) { - const result = content - .replace(RegExp(defName, 'g'), newName) - .replace(RegExp(camelize(defName), 'g'), camelize(newName)) - .replace( - RegExp(ucfirst(camelize(defName)), 'g'), - ucfirst(camelize(newName)) - ); - - if (runner != null) { - return result.replace(/runner/g, runner); - } - - return result; - } - /** @override */ constructor(config, vfs, log) { super(config, vfs, log); diff --git a/src/controllers/make.js b/src/controllers/make.js index 3a4bd70..3d5cefa 100644 --- a/src/controllers/make.js +++ b/src/controllers/make.js @@ -1,15 +1,23 @@ const {Controller} = require('../core/controller'); class MakeController extends Controller { - async run() { - const prefix = this.config.subject === 'block' ? 'b' : 'p', - name = this.resolveName(this.config.name, prefix); + resolvedName; - const source = this.vfs.resolve(__dirname, '../templates/component'), + /** @override */ + async run() { + const + name = this.resolveName(this.config.name, this.prefix), + source = this.vfs.resolve(__dirname, '../templates/component'), + secondarySource = this.vfs.resolve(__dirname, '../templates/component', this.config.template), destination = this.vfs.resolve(this.config.path, name); + this.handlebarsOptions = {name, clearName: this.config.name}; + + await this.vfs.ensureDir(secondarySource); await this.vfs.ensureDir(destination); - this.copyFolder(source, destination, name); + + await this.copyDir(source, destination, {withFolders: false}); + await this.copyDir(secondarySource, destination, {withFolders: true}); } } diff --git a/src/core/config.js b/src/core/config.js index 74d85d0..7cea436 100644 --- a/src/core/config.js +++ b/src/core/config.js @@ -38,7 +38,7 @@ class Config { return './src/pages'; case 'block': - return './src/base'; + return './src/components'; default: return './'; diff --git a/src/core/controller.js b/src/core/controller.js index d4a5f95..10e10d3 100644 --- a/src/core/controller.js +++ b/src/core/controller.js @@ -1,3 +1,5 @@ +const path = require('path'); +const {getOutputFileInfo, Handlebars} = require('./handlebars'); const {camelize, ucfirst, gitUser} = require('./helpers'); /** @@ -19,6 +21,20 @@ class Controller { */ log; + /** + * @type {Dictionary} + */ + handlebarsOptions; + + /** + * Prefix for a current subject + * + * @returns {string} + */ + get prefix() { + return this.config.subject === 'page' ? 'p' : 'b'; + } + /** * @param {IConfig} config * @param {VirtualFileSystem} vfs @@ -33,52 +49,30 @@ class Controller { /** * @param {string} name * @param {string} [prefix] + * @param {boolean} [withPrefix] * @returns {string} */ - resolveName(name, prefix = 'b') { - return /^[bp]-/.test(name) ? name : `${prefix}-${name}`; + resolveName(name, prefix = 'b', withPrefix = true) { + const + localName = name.split(path.sep).length === 1 ? name : name.split(path.sep).at(-1); + + if (withPrefix) { + return /^[bp]-/.test(localName) ? localName : `${prefix}-${localName}`; + } + + return name.split(path.sep).at(-1).replace(/^[bp]-/g, ''); } /** - * Copy files and directories from source to destination + * Copies directory * * @param {string} source * @param {string} destination - * @param {string} name - * @param {boolean} withFolders - * @private + * @param {CopyDirOptions} options + * @returns {Promise} */ - copyFolder(source, destination, name, withFolders = false) { - const files = this.vfs.readdir(source); - - for (const file of files) { - const fileName = this.vfs.resolve(source, file); - - if (this.vfs.isDirectory(fileName)) { - if (withFolders) { - this.log.msg(`Directory:${fileName}`); - this.vfs.ensureDir(this.vfs.resolve(destination, file)); - this.copyFolder( - fileName, - this.vfs.resolve(destination, file), - name, - true - ); - } else if (file === this.config.template) { - this.copyFolder(fileName, destination, name); - } - - continue; - } - - const data = this.vfs.readFile(fileName), - newFile = this.vfs.resolve(destination, this.replaceNames(file, name)); - - if (!this.vfs.exists(newFile) || this.config.override) { - this.log.msg(`File:${newFile}`); - this.vfs.writeFile(newFile, this.replaceNames(data, name)); - } - } + copyDir(source, destination, options) { + return this.copy(source, destination, options); } /** @@ -119,6 +113,79 @@ class Controller { return result; } + + /** + * Copies and resolves template + * + * @param {string} sourceFile + * @param {string} destinationFolder + * @returns {Promise} + * @protected + */ + async resolveTemplate(sourceFile, destinationFolder) { + let + {outputName, ext} = await getOutputFileInfo(sourceFile); + + if (outputName === '[[name]]' || outputName == null) { + outputName = this.handlebarsOptions.name; + } + + this.vfs.writeFile( + `${destinationFolder}${path.sep}${outputName}.${ext}`, + Handlebars.compile(this.vfs.readFile(sourceFile))(this.handlebarsOptions) + ); + } + + /** + * Copies directory + * + * @param {string} source + * @param {string} destination + * @param {CopyDirOptions} options + * @param {string[]} pathStack + * @returns {Promise} + * @protected + */ + async copy(source, destination, options = {}, pathStack = []) { + const + {withFolders = true} = options; + + const + curSource = this.vfs.resolve(source, ...pathStack), + isDirectory = this.vfs.isDirectory(curSource); + + if (isDirectory) { + const + promises = []; + + for (const file of this.vfs.readdir(curSource)) { + if (!withFolders && this.vfs.isDirectory(this.vfs.resolve(curSource, file))) { + continue; + } + + promises.push(this.copy(source, destination, options, [...pathStack, file])); + } + + await Promise.all(promises); + return; + } + + const + curDestinationFolder = this.vfs.resolve(destination, ...pathStack.slice(0, pathStack.length - 1)), + extname = this.vfs.extname(pathStack.at(-1)); + + await this.vfs.ensureDir(curDestinationFolder); + + if (extname === '.handlebars' || extname === '.hbs') { + await this.resolveTemplate(curSource, curDestinationFolder); + return; + } + + this.vfs.writeFile( + this.vfs.resolve(destination, ...pathStack), + this.vfs.readFile(curSource) + ); + } } exports.Controller = Controller; diff --git a/src/core/handlebars.js b/src/core/handlebars.js new file mode 100644 index 0000000..b792d80 --- /dev/null +++ b/src/core/handlebars.js @@ -0,0 +1,56 @@ +/* eslint-disable func-names */ +const Handlebars = require('handlebars'); + +const {camelize, ucfirst, readFirstLine} = require('./helpers'); + +/** + * Camelize string + * @param {string} str + */ +Handlebars.registerHelper('camelize', function (options) { + return camelize(options.fn(this)); +}); + +/** + * Camelize string and upper case first char + */ +Handlebars.registerHelper('capitalize', function (options) { + return ucfirst(camelize(options.fn(this))); +}); + +/** + * Wrap content in these quotes ``` + */ +Handlebars.registerHelper('wrapInCodeBlock', function (options) { + // eslint-disable-next-line prefer-template + return Handlebars.SafeString('```\n' + options.fn(this) + '\n```'); +}); + +/** + * Reads the template that returns output file info + * The first line of the template contains information about the file name and extension + * The format looks like this: {{! name=index ext=ts }} + * It will be parsed into this: {name: 'index', ext: 'ts'} + * + * @param {string} path + * @returns {Promise<{ext: string; outputName?: string}>} + */ +async function getOutputFileInfo(path) { + const + line = await readFirstLine(path), + opts = line.slice(4, -3).trim().split(/\s+/); + + return opts.reduce((acc, el) => { + const + tuple = el.split('='); + + return { + ...acc, + [tuple[0]]: tuple[1] + }; + }, {}); +} + +module.exports.Handlebars = Handlebars; + +module.exports.getOutputFileInfo = getOutputFileInfo; diff --git a/src/core/helpers.js b/src/core/helpers.js index 449f638..cc3fb46 100644 --- a/src/core/helpers.js +++ b/src/core/helpers.js @@ -1,3 +1,8 @@ +const fs = require('fs'); +const readline = require('readline'); +const gitconfig = require('git-config-path'); +const parse = require('parse-git-config'); + /** * Camelize string * @param {string} str @@ -11,9 +16,6 @@ exports.camelize = (str) => */ exports.ucfirst = (str) => str[0].toUpperCase() + str.substr(1); -const gitconfig = require('git-config-path'), - parse = require('parse-git-config'); - /** * Current user name */ @@ -36,3 +38,31 @@ exports.gitUser = (() => { email: config.user.name || config.user.email || defaultUser.email }; })(); + +/** + * Read the first line from the file + * @param {string} path + */ +exports.readFirstLine = (path) => { + const rl = readline.createInterface({ + input: fs.createReadStream(path) + }); + + let + resolve, + reject; + + const res = new Promise((res, rej) => { + resolve = res; + reject = rej; + }); + + try { + rl.once('line', (line) => resolve(line)); + + } catch (error) { + reject(error); + } + + return res; +}; diff --git a/src/core/interface.ts b/src/core/interface.ts index 6fbb7de..38d59f3 100644 --- a/src/core/interface.ts +++ b/src/core/interface.ts @@ -5,11 +5,15 @@ interface IConfig { path: string; name: string; newName?: string; - subject: 'block' | 'page' | 'app' | 'test'; + subject: 'block' | 'page'; command?: 'make' | 'rename'; _: [this['command']]; reporter: 'json' | 'raw' | 'silent'; template: 'default' | 'mono' | 'functional'; extend: 'default' | 'i-block' | 'i-data' | 'i-dynamic-page' | 'i-static-page'; - runners?: string[]; + target?: string; +} + +interface CopyDirOptions { + withFolders?: boolean; } diff --git a/src/core/vfs.js b/src/core/vfs.js index 92fb268..371e1f4 100644 --- a/src/core/vfs.js +++ b/src/core/vfs.js @@ -106,6 +106,15 @@ class VirtualFileSystem { return fs.readdirSync(filepath); } + /** + * Copy directory + * + * @param {string} filepath + */ + copyDir(filepath) { + return fs.cpSync() + } + /** * Remove directory * diff --git a/src/templates/app/package.json b/src/templates/app/package.json.handlebars similarity index 81% rename from src/templates/app/package.json rename to src/templates/app/package.json.handlebars index ab6fd93..d1cf5ee 100644 --- a/src/templates/app/package.json +++ b/src/templates/app/package.json.handlebars @@ -1,7 +1,8 @@ +{{! outputName=package ext=json }} { - "name": "b-name", + "name": "{{name}}", "version": "1.0.0", - "description": "Description b-name", + "description": "Description {{name}}", "scripts": { "build": "gulp build:tsconfig && webpack --watch --debug false", "start": "node webview.app", @@ -9,7 +10,7 @@ }, "author": "@YourFullName", "keywords": [ - "b-name" + "{{name}}" ], "dependencies": { "@v4fire/client": "^3.0.0-rc.59", diff --git a/src/templates/app/src/base/b-hello-world/index.js b/src/templates/app/src/base/b-hello-world/index.js index c5d29f1..660317c 100644 --- a/src/templates/app/src/base/b-hello-world/index.js +++ b/src/templates/app/src/base/b-hello-world/index.js @@ -1,2 +1,2 @@ package('b-hello-world') - .extends('i-block'); + .extends('i-block'); diff --git a/src/templates/component/README.handlebars b/src/templates/component/README.handlebars new file mode 100644 index 0000000..e1ecf45 --- /dev/null +++ b/src/templates/component/README.handlebars @@ -0,0 +1,12 @@ +{{! outputName=README ext=md }} +# components/{{name}} + +[Changelog](./CHANGELOG.md) + +About {{#camelize}}{{name}}{{/camelize}} + +## How to use + +{{#wrapInCodeBlock}} +< {{name}} +{{/wrapInCodeBlock}} diff --git a/src/templates/component/README.md b/src/templates/component/README.md deleted file mode 100644 index 0cd0ea9..0000000 --- a/src/templates/component/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# base/b-name - -[Changelog](./CHANGELOG.md) - -About bName - -## How to use - -``` -< b-name -``` diff --git a/src/templates/component/b-name.styl b/src/templates/component/b-name.styl deleted file mode 100644 index fe0cd8a..0000000 --- a/src/templates/component/b-name.styl +++ /dev/null @@ -1,7 +0,0 @@ -@import "super/i-block/i-block.styl" - -$p = { - -} - -b-name extends i-block diff --git a/src/templates/component/default/b-name.ts b/src/templates/component/default/b-name.ts deleted file mode 100644 index 5be15e9..0000000 --- a/src/templates/component/default/b-name.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * [[include:base/b-name/README.md]] - * @packageDocumentation - */ - -import iBlock, { component } from 'super/i-block/i-block'; - -export * from 'super/i-block/i-block'; - -/** - * BName - */ -@component() -export default class bName extends iBlock {} diff --git a/src/templates/component/functional/b-name.ss b/src/templates/component/default/tpl-ss.handlebars similarity index 80% rename from src/templates/component/functional/b-name.ss rename to src/templates/component/default/tpl-ss.handlebars index b0beaf4..831b169 100644 --- a/src/templates/component/functional/b-name.ss +++ b/src/templates/component/default/tpl-ss.handlebars @@ -1,3 +1,4 @@ +{{! outputName=[[name]] ext=ss }} - namespace [%fileName%] - include 'super/i-block'|b as placeholder diff --git a/src/templates/component/default/tpl-ts.handlebars b/src/templates/component/default/tpl-ts.handlebars new file mode 100644 index 0000000..9dc534a --- /dev/null +++ b/src/templates/component/default/tpl-ts.handlebars @@ -0,0 +1,15 @@ +{{! outputName=[[name]] ext=ts }} +/** + * [[include:components/{{name}}/README.md]] + * @packageDocumentation + */ + +import iBlock, { component } from 'super/i-block/i-block'; + +export * from 'super/i-block/i-block'; + +/** + * {{#capitalize}}{{name}}{{/capitalize}} + */ +@component() +export default class {{#camelize}}{{name}}{{/camelize}} extends iBlock {} diff --git a/src/templates/component/functional/b-name.ts b/src/templates/component/functional/b-name.ts deleted file mode 100644 index 408f203..0000000 --- a/src/templates/component/functional/b-name.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * [[include:base/b-name/README.md]] - * @packageDocumentation - */ - -import iBlock, { component } from 'super/i-block/i-block'; - -export * from 'super/i-block/i-block'; - -/** - * BName - */ -@component({functional: true}) -export default class bName extends iBlock {} diff --git a/src/templates/component/default/b-name.ss b/src/templates/component/functional/tpl-ss.handlebars similarity index 80% rename from src/templates/component/default/b-name.ss rename to src/templates/component/functional/tpl-ss.handlebars index b0beaf4..831b169 100644 --- a/src/templates/component/default/b-name.ss +++ b/src/templates/component/functional/tpl-ss.handlebars @@ -1,3 +1,4 @@ +{{! outputName=[[name]] ext=ss }} - namespace [%fileName%] - include 'super/i-block'|b as placeholder diff --git a/src/templates/component/functional/tpl-ts.handlebars b/src/templates/component/functional/tpl-ts.handlebars new file mode 100644 index 0000000..342a36b --- /dev/null +++ b/src/templates/component/functional/tpl-ts.handlebars @@ -0,0 +1,15 @@ +{{! outputName=[[name]] ext=ts }} +/** + * [[include:components/{{name}}/README.md]] + * @packageDocumentation + */ + +import iBlock, { component } from 'super/i-block/i-block'; + +export * from 'super/i-block/i-block'; + +/** + * {{#capitalize}}{{name}}{{/capitalize}} + */ +@component({functional: true}) +export default class {{#camelize}}{{name}}{{/camelize}} extends iBlock {} diff --git a/src/templates/component/index.handlebars b/src/templates/component/index.handlebars new file mode 100644 index 0000000..27d71ae --- /dev/null +++ b/src/templates/component/index.handlebars @@ -0,0 +1,3 @@ +{{! outputName=index ext=js }} +package('{{name}}') + .extends('i-block'); diff --git a/src/templates/component/index.js b/src/templates/component/index.js deleted file mode 100644 index 85af400..0000000 --- a/src/templates/component/index.js +++ /dev/null @@ -1,2 +0,0 @@ -package('b-name') - .extends('i-block'); diff --git a/src/templates/component/mono/b-name.ss b/src/templates/component/mono/tpl-ss.handlebars similarity index 82% rename from src/templates/component/mono/b-name.ss rename to src/templates/component/mono/tpl-ss.handlebars index 47bfebd..810e71e 100644 --- a/src/templates/component/mono/b-name.ss +++ b/src/templates/component/mono/tpl-ss.handlebars @@ -1,3 +1,4 @@ +{{! outputName=[[name]] ext=ss }} - namespace [%fileName%] - include 'super/i-block'|b as placeholder diff --git a/src/templates/component/tpl-styl.handlebars b/src/templates/component/tpl-styl.handlebars new file mode 100644 index 0000000..04c51b0 --- /dev/null +++ b/src/templates/component/tpl-styl.handlebars @@ -0,0 +1,8 @@ +{{! outputName=[[name]] ext=ss }} +@import "super/i-block/i-block.styl" + +$p = { + +} + +{{name}} extends i-block diff --git a/src/templates/test/block/mock-data.ts b/src/templates/test/block/mock-data.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/templates/test/block/unit/tpl.handlebars b/src/templates/test/block/unit/tpl.handlebars new file mode 100644 index 0000000..2b0fe33 --- /dev/null +++ b/src/templates/test/block/unit/tpl.handlebars @@ -0,0 +1,34 @@ +{{! outputName=main ext=ts }} +import type { JSHandle } from 'playwright'; + +import test from 'tests/config/unit/test'; +import Component from 'tests/helpers/component'; + +import type {{#camelize}}{{name}}{{/camelize}} from 'src/components/{{name}}/{{name}}.ts'; + +test.describe('<{{name}}>', () => { + const scheme = [ + { + attrs: { + id: '{{name}}-component' + } + } + ]; + + let + node: JSHandle, + component: JSHandle<{{#camelize}}{{name}}{{/camelize}}>; + + test.beforeEach(async ({ demoPage, page }) => { + await demoPage.goto(); + await Component.createComponent(page, '{{name}}', scheme); + }); + + test('should be rendered', async ({ page }) => { + const + component = await Component.getComponentByQuery(page, '#{{name}}-component'), + componentName = await component.getProperty('componentName'); + + await test.expect(componentName.jsonValue()).resolves.toBe('{{name}}'); + }); +}); diff --git a/src/templates/test/component/simple/index.js b/src/templates/test/component/simple/index.js deleted file mode 100644 index 205055f..0000000 --- a/src/templates/test/component/simple/index.js +++ /dev/null @@ -1,48 +0,0 @@ -// @ts-check - -const h = include('tests/helpers'); - -/** - * Tests for b-name - * - * @param {Playwright.Page} page - * @param {!Object} params - * - * @returns {!Promise} - */ -module.exports = async (page, params) => { - await h.utils.setup(page, params.context); - - describe('b-name', () => { - let - bNameComponent, - bNameNode; - - const scheme = [ - { - attrs: { - id: 'b-name-component' - } - } - ]; - - beforeEach(async () => { - await page.evaluate((scheme) => { - globalThis.removeCreatedComponents(); - globalThis.renderComponents('b-name', scheme); - }, scheme); - - bNameComponent = await h.component.getComponentById( - page, - 'b-name-component' - ); - - bNameNode = await page.$('#b-name-component'); - }); - - it('works', () => { - expect(bNameComponent).toBeTruthy(); - expect(bNameNode).toBeTruthy(); - }); - }); -}; diff --git a/src/templates/test/component/with-runners/index.js b/src/templates/test/component/with-runners/index.js deleted file mode 100644 index 29f4522..0000000 --- a/src/templates/test/component/with-runners/index.js +++ /dev/null @@ -1,18 +0,0 @@ -// @ts-check - -const h = include('tests/helpers'), - u = include('tests/utils'), - test = u.getCurrentTest(); - -/** - * Starts b-name tests - * - * @param {Playwright.Page} page - * @param {!Object} params - * - * @returns {!Promise} - */ -module.exports = async (page, params) => { - await h.utils.setup(page, params.context); - await test(page, params); -}; diff --git a/src/templates/test/component/with-runners/runners/runner.js b/src/templates/test/component/with-runners/runners/runner.js deleted file mode 100644 index 67d87df..0000000 --- a/src/templates/test/component/with-runners/runners/runner.js +++ /dev/null @@ -1,41 +0,0 @@ -// @ts-check - -const h = include('tests/helpers'); - -/** - * @param {Playwright.Page} page - */ -module.exports = (page) => { - describe('b-name runner', () => { - let - bNameComponent, - bNameNode; - - const scheme = [ - { - attrs: { - id: 'b-name-component' - } - } - ]; - - beforeEach(async () => { - await page.evaluate((scheme) => { - globalThis.removeCreatedComponents(); - globalThis.renderComponents('b-name', scheme); - }, scheme); - - bNameComponent = await h.component.getComponentById( - page, - 'b-name-component' - ); - - bNameNode = await page.$('#b-name-component'); - }); - - it('works', () => { - expect(bNameComponent).toBeTruthy(); - expect(bNameNode).toBeTruthy(); - }); - }); -}; diff --git a/src/templates/test/module/simple/index.js b/src/templates/test/module/simple/index.js deleted file mode 100644 index 80a6e6b..0000000 --- a/src/templates/test/module/simple/index.js +++ /dev/null @@ -1,35 +0,0 @@ -// @ts-check - -const h = include('tests/helpers'); - -/** - * Tests for name - * - * @param {Playwright.Page} page - * @param {!Object} params - * - * @returns {!Promise} - */ -module.exports = async (page, params) => { - await h.utils.setup(page, params.context); - - describe('name', () => { - let - bDummyComponent, - bDummyNode; - - beforeAll(async () => { - bDummyComponent = await h.component.getComponentById( - page, - 'dummy-component' - ); - - bDummyNode = await h.dom.waitForEl(page, '#dummy-component'); - }); - - it('works', () => { - expect(bDummyComponent).toBeTruthy(); - expect(bDummyNode).toBeTruthy(); - }); - }); -}; diff --git a/src/templates/test/module/with-runners/index.js b/src/templates/test/module/with-runners/index.js deleted file mode 100644 index 024ea81..0000000 --- a/src/templates/test/module/with-runners/index.js +++ /dev/null @@ -1,18 +0,0 @@ -// @ts-check - -const h = include('tests/helpers'), - u = include('tests/utils'), - test = u.getCurrentTest(); - -/** - * Starts name tests - * - * @param {Playwright.Page} page - * @param {!Object} params - * - * @returns {!Promise} - */ -module.exports = async (page, params) => { - await h.utils.setup(page, params.context); - await test(page, params); -}; diff --git a/src/templates/test/module/with-runners/runners/runner.js b/src/templates/test/module/with-runners/runners/runner.js deleted file mode 100644 index 2b18aa0..0000000 --- a/src/templates/test/module/with-runners/runners/runner.js +++ /dev/null @@ -1,28 +0,0 @@ -// @ts-check - -const h = include('tests/helpers'); - -/** - * @param {Playwright.Page} page - */ -module.exports = (page) => { - describe('name runner', () => { - let - bDummyComponent, - bDummyNode; - - beforeAll(async () => { - bDummyComponent = await h.component.getComponentById( - page, - 'b-dummy-component' - ); - - bDummyNode = await h.dom.waitForEl(page, '#b-dummy-component'); - }); - - it('works', () => { - expect(bDummyComponent).toBeTruthy(); - expect(bDummyNode).toBeTruthy(); - }); - }); -}; diff --git a/src/templates/test/page/mock-data.ts b/src/templates/test/page/mock-data.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/templates/test/page/project/tpl.handlebars b/src/templates/test/page/project/tpl.handlebars new file mode 100644 index 0000000..5454d3e --- /dev/null +++ b/src/templates/test/page/project/tpl.handlebars @@ -0,0 +1,8 @@ +{{! outputName=main ext=ts }} +import test from 'tests/config/project/test'; + +test.describe('<{{name}}>', () => { + test('should be rendered', async ({ {{#camelize}}{{name}}{{/camelize}}, page }) => { + await test.expect(page.locator('.{{name}}')).toBeVisible(); + }); +}); diff --git a/tests/cli.test.js b/tests/cli.test.js index 07a388e..9f4a57a 100644 --- a/tests/cli.test.js +++ b/tests/cli.test.js @@ -46,7 +46,7 @@ describe('Cli test', () => { }); app.run().then(() => { - expect(app.vfs.exists('./src/base/b-point/b-point.ss')).is.true; + expect(app.vfs.exists('./src/components/b-point/b-point.ss')).is.true; exec( 'node', @@ -61,8 +61,8 @@ describe('Cli test', () => { throw error; } - expect(app.vfs.exists('./src/base/b-point/b-point.ss')).is.false; - expect(app.vfs.exists('./src/base/b-time/b-time.ss')).is.true; + expect(app.vfs.exists('./src/components/b-point/b-point.ss')).is.false; + expect(app.vfs.exists('./src/components/b-time/b-time.ss')).is.true; done(); } diff --git a/tests/command.test.js b/tests/command.test.js index 3adb4e1..3090951 100644 --- a/tests/command.test.js +++ b/tests/command.test.js @@ -12,7 +12,7 @@ describe('Exec command', () => { await app.run(); - expect(app.vfs.exists('./src/base/b-test/b-test.ss')).is.true; + expect(app.vfs.exists('./src/components/b-test/b-test.ss')).is.true; }); }); @@ -26,9 +26,9 @@ describe('Exec command', () => { await app.run(); - expect(app.vfs.exists('./src/base/b-test/b-test.ss')).is.true; - expect(app.vfs.exists('./src/base/b-test/CHANGELOG.md')).is.true; - expect(app.vfs.exists('./src/base/b-test/README.md')).is.true; + expect(app.vfs.exists('./src/components/b-test/b-test.ss')).is.true; + expect(app.vfs.exists('./src/components/b-test/CHANGELOG.md')).is.true; + expect(app.vfs.exists('./src/components/b-test/README.md')).is.true; const app2 = getApplication({ command: 'rename', @@ -38,15 +38,15 @@ describe('Exec command', () => { await app2.run(); - expect(app2.vfs.exists('./src/base/b-test/b-test.ss')).is.false; - expect(app2.vfs.exists('./src/base/b-plot/b-plot.ss')).is.true; - expect(app2.vfs.exists('./src/base/b-plot/CHANGELOG.md')).is.true; - expect(app2.vfs.exists('./src/base/b-plot/README.md')).is.true; - expect(app2.vfs.readFile('./src/base/b-plot/b-plot.ts')).contains( + expect(app2.vfs.exists('./src/components/b-test/b-test.ss')).is.false; + expect(app2.vfs.exists('./src/components/b-plot/b-plot.ss')).is.true; + expect(app2.vfs.exists('./src/components/b-plot/CHANGELOG.md')).is.true; + expect(app2.vfs.exists('./src/components/b-plot/README.md')).is.true; + expect(app2.vfs.readFile('./src/components/b-plot/b-plot.ts')).contains( 'bPlot' ); - expect(app2.vfs.readFile('./src/base/b-plot/b-plot.styl')).contains( + expect(app2.vfs.readFile('./src/components/b-plot/b-plot.styl')).contains( 'b-plot' ); }); @@ -61,7 +61,7 @@ describe('Exec command', () => { await app.run(); - expect(app.vfs.readFile('./src/base/b-test/b-test.ts')).contains( + expect(app.vfs.readFile('./src/components/b-test/b-test.ts')).contains( 'extends iData' ); @@ -73,44 +73,24 @@ describe('Exec command', () => { }); await app2.run(); - expect(app2.vfs.readFile('./src/base/b-plot/b-plot.ts')).contains( + expect(app2.vfs.readFile('./src/components/b-plot/b-plot.ts')).contains( 'extends iData' ); }); }); describe('Make test', () => { - it('should create test without runners', async () => { + it('should create test without path', async () => { const app = getApplication({ - path: 'src/base/b-slider', command: 'make-test', - runners: [] - }); - - await app.run(); - - expect(app.vfs.exists('./src/base/b-slider/test/index.js')).is.true; - expect(app.vfs.exists('./src/base/b-slider/test/runners')).is.false; - }); - - it('should create test with runners', async () => { - const app = getApplication({ - path: 'src/base/b-slider', - command: 'make-test', - runners: ['analytics', 'events', 'render'] + subject: 'block', + target: 'b-slider' }); await app.run(); - expect(app.vfs.exists('./src/base/b-slider/test/index.js')).is.true; - expect(app.vfs.exists('./src/base/b-slider/test/runners/analytics.js')).is - .true; - - expect(app.vfs.exists('./src/base/b-slider/test/runners/events.js')).is - .true; - - expect(app.vfs.exists('./src/base/b-slider/test/runners/render.js')).is - .true; + expect(app.vfs.exists('./src/components/b-slider/test/mock-data.ts')).is.true; + expect(app.vfs.exists('./src/components/b-slider/test/unit/main.ts')).is.false; }); }); }); diff --git a/tests/extend.test.js b/tests/extend.test.js index be8e3d3..3fbaa77 100644 --- a/tests/extend.test.js +++ b/tests/extend.test.js @@ -13,12 +13,12 @@ describe('Change extend option', () => { await app.run(); - expect(app.vfs.exists('./src/base/b-test/b-test.ss')).is.true; - expect(app.vfs.readFile('./src/base/b-test/b-test.ts')).contains( + expect(app.vfs.exists('./src/components/b-test/b-test.ss')).is.true; + expect(app.vfs.readFile('./src/components/b-test/b-test.ts')).contains( 'i-data/i-data' ); - expect(app.vfs.readFile('./src/base/b-test/b-test.ts')).contains( + expect(app.vfs.readFile('./src/components/b-test/b-test.ts')).contains( 'extends iData' ); }); diff --git a/tests/path.test.js b/tests/path.test.js index daa05ce..3913d14 100644 --- a/tests/path.test.js +++ b/tests/path.test.js @@ -7,12 +7,12 @@ describe('Change path option', () => { command: 'make', subject: 'block', name: 'test', - path: './src/base/test/best/pop/' + path: './src/components/test/best/pop/' }); await app.run(); - expect(app.vfs.exists('./src/base/test/best/pop/b-test/b-test.ss')).is.true; + expect(app.vfs.exists('./src/components/test/best/pop/b-test/b-test.ss')).is.true; }); it('should change relative path inside .md files', async () => { @@ -20,17 +20,17 @@ describe('Change path option', () => { command: 'make', subject: 'block', name: 'test', - path: './src/base/test/best/pop/' + path: './src/components/test/best/pop/' }); await app.run(); expect( - app.vfs.readFile('./src/base/test/best/pop/b-test/b-test.ts') - ).contains('[[include:base/test/best/pop/b-test/README.md]]'); + app.vfs.readFile('./src/components/test/best/pop/b-test/b-test.ts') + ).contains('[[include:components/test/best/pop/b-test/README.md]]'); expect( - app.vfs.readFile('./src/base/test/best/pop/b-test/README.md') - ).contains('# base/test/best/pop/b-test'); + app.vfs.readFile('./src/components/test/best/pop/b-test/README.md') + ).contains('# components/test/best/pop/b-test'); }); }); diff --git a/tests/staff/helpers.js b/tests/staff/helpers.js index b5a4d27..ede12b4 100644 --- a/tests/staff/helpers.js +++ b/tests/staff/helpers.js @@ -1,4 +1,5 @@ const {Application} = require('../../src/application'); +const {VirtualFileSystem} = require('../../src/core/vfs'); /** * @param {IConfig} options @@ -12,4 +13,11 @@ function getApplication(options) { }); } -module.exports.getApplication = getApplication; +/** + * @returns {VirtualFileSystem} + */ +function getVFS() { + return new VirtualFileSystem(); +} + +module.exports = {getApplication, getVFS}; diff --git a/tests/template.test.js b/tests/template.test.js index 05c32d3..2ab6404 100644 --- a/tests/template.test.js +++ b/tests/template.test.js @@ -1,133 +1,132 @@ const {expect} = require('chai'); -const {getApplication} = require('./staff/helpers'); +const {getApplication, getVFS} = require('./staff/helpers'); describe('Change template option', () => { - describe('Make', () => { - describe('mono', () => { - it('should create mono component', async () => { + const + commonVfs = getVFS(); + + describe('`make`', () => { + const + componentName = 'b-test', + componentDir = commonVfs.resolve('src', 'components', componentName); + + after(() => { + if (commonVfs.exists(componentDir)) { + commonVfs.rmDir(componentDir); + } + }); + + describe('`mono`', () => { + it('should create `mono` component', async () => { const app = getApplication({ command: 'make', subject: 'block', - name: 'test', + name: componentName, template: 'mono' }); await app.run(); - expect(app.vfs.exists('./src/base/b-test/b-test.ss')).is.true; - expect(app.vfs.exists('./src/base/b-test/b-test.styl')).is.true; - expect(app.vfs.exists('./src/base/b-test/b-test.ts')).is.false; - expect(app.vfs.readFile('./src/base/b-test/b-test.ss')).contains( + expect(app.vfs.exists(`${componentDir}/${componentName}.ss`)).is.true; + expect(app.vfs.exists(`${componentDir}/${componentName}.styl`)).is.true; + expect(app.vfs.exists(`${componentDir}/${componentName}.ts`)).is.false; + expect(app.vfs.readFile(`${componentDir}/${componentName}.ss`)).contains( '- @@ignore' ); }); }); - describe('functional', () => { - it('should create functional component', async () => { + describe('`functional`', () => { + it('should create `functional` component', async () => { const app = getApplication({ command: 'make', subject: 'block', - name: 'test', + name: componentName, template: 'functional' }); await app.run(); - expect(app.vfs.exists('./src/base/b-test/b-test.ss')).is.true; - expect(app.vfs.exists('./src/base/b-test/b-test.styl')).is.true; - expect(app.vfs.exists('./src/base/b-test/b-test.ts')).is.true; - expect(app.vfs.readFile('./src/base/b-test/b-test.ts')).contains( + expect(app.vfs.exists(`${componentDir}/${componentName}.ss`)).is.true; + expect(app.vfs.exists(`${componentDir}/${componentName}.styl`)).is.true; + expect(app.vfs.exists(`${componentDir}/${componentName}.ts`)).is.true; + expect(app.vfs.readFile(`${componentDir}/${componentName}.ts`)).contains( '@component({functional: true})' ); }); }); }); - describe('Make test', () => { - describe('for component', () => { - it('should provide name of component', async () => { - const app = getApplication({ - path: 'src/base/b-slider', - command: 'make-test', - runners: [] - }); + describe('`make-test`', () => { + const + componentDir = 'src/components/b-test', + pageDir = 'src/pages/p-test'; - await app.run(); + let + testFileText; - const testFileText = app.vfs.readFile( - './src/base/b-slider/test/index.js' - ); + after(() => { + if (commonVfs.exists(componentDir)) { + commonVfs.rmDir(componentDir); + } - expect(testFileText).contains('b-slider'); - expect(testFileText).contains('bSlider'); - expect(testFileText).not.contains('bDummy'); - expect(testFileText).not.contains('b-dummy'); - expect(testFileText).not.contains('bName'); - expect(testFileText).not.contains('b-name'); - }); + if (commonVfs.exists(pageDir)) { + commonVfs.rmDir(pageDir); + } + }); - it('should provide name of component in runner', async () => { + describe('`block`', () => { + beforeEach(async () => { const app = getApplication({ - path: 'src/base/b-slider', command: 'make-test', - runners: ['events'] + subject: 'block', + target: componentDir }); await app.run(); + testFileText = app.vfs.readFile(`${componentDir}/test/unit/main.ts`); + }); - const runnerFileText = app.vfs.readFile( - './src/base/b-slider/test/runners/events.js' - ); + it('should provide name of component', () => { + expect(testFileText).contains('b-test'); + expect(testFileText).contains('Test'); + }); - expect(runnerFileText).contains('b-slider'); - expect(runnerFileText).contains('bSlider'); - expect(runnerFileText).contains('events'); - expect(runnerFileText).not.contains('runner'); - expect(runnerFileText).not.contains('bDummy'); - expect(runnerFileText).not.contains('b-dummy'); - expect(runnerFileText).not.contains('bName'); - expect(runnerFileText).not.contains('b-name'); + it('should`t contain any replacers', () => { + expect(testFileText).not.contains('b-name'); + expect(testFileText).not.contains('bName'); + expect(testFileText).not.contains('BName'); + expect(testFileText).not.contains('r-name'); + expect(testFileText).not.contains('rName'); + expect(testFileText).not.contains('RName'); }); }); - describe('for module', () => { - it('should provide name of module', async () => { + describe('`page`', () => { + beforeEach(async () => { const app = getApplication({ - path: 'src/base/some-module', command: 'make-test', - runners: [] + subject: 'page', + target: pageDir }); await app.run(); - const testFileText = app.vfs.readFile( - './src/base/some-module/test/index.js' - ); - - expect(testFileText).contains('some-module'); - expect(testFileText).contains('bDummy'); - expect(testFileText).not.contains('name'); + testFileText = app.vfs.readFile(`${pageDir}/test/project/main.ts`); }); - it('should provide name of module in runner', async () => { - const app = getApplication({ - path: 'src/base/some-module', - command: 'make-test', - runners: ['events'] - }); - - await app.run(); - - const runnerFileText = app.vfs.readFile( - './src/base/some-module/test/runners/events.js' - ); + it('should provide name of page', () => { + expect(testFileText).contains('p-test'); + expect(testFileText).contains('Test'); + }); - expect(runnerFileText).contains('some-module'); - expect(runnerFileText).contains('bDummy'); - expect(runnerFileText).contains('b-dummy'); - expect(runnerFileText).not.contains('runner'); - expect(runnerFileText).not.contains('name'); + it('should`t contain any replacers', () => { + expect(testFileText).not.contains('p-name'); + expect(testFileText).not.contains('pName'); + expect(testFileText).not.contains('PName'); + expect(testFileText).not.contains('r-name'); + expect(testFileText).not.contains('rName'); + expect(testFileText).not.contains('RName'); }); }); }); diff --git a/yarn.lock b/yarn.lock index 4dc40e7..e6783c7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2433,6 +2433,7 @@ __metadata: fs-extra: 11.1.1 git-config-path: 2.0.0 glob: 9.3.4 + handlebars: 4.7.7 mocha: 10.2.0 parse-git-config: 3.0.0 typescript: 4.4.4 @@ -6384,6 +6385,24 @@ __metadata: languageName: node linkType: hard +"handlebars@npm:4.7.7": + version: 4.7.7 + resolution: "handlebars@npm:4.7.7" + dependencies: + minimist: ^1.2.5 + neo-async: ^2.6.0 + source-map: ^0.6.1 + uglify-js: ^3.1.4 + wordwrap: ^1.0.0 + dependenciesMeta: + uglify-js: + optional: true + bin: + handlebars: bin/handlebars + checksum: 1e79a43f5e18d15742977cb987923eab3e2a8f44f2d9d340982bcb69e1735ed049226e534d7c1074eaddaf37e4fb4f471a8adb71cddd5bc8cf3f894241df5cee + languageName: node + linkType: hard + "has-ansi@npm:^2.0.0": version: 2.0.0 resolution: "has-ansi@npm:2.0.0" @@ -7887,13 +7906,20 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:^7.14.1, lru-cache@npm:^7.7.1": +"lru-cache@npm:^7.7.1": version: 7.18.3 resolution: "lru-cache@npm:7.18.3" checksum: e550d772384709deea3f141af34b6d4fa392e2e418c1498c078de0ee63670f1f46f5eee746e8ef7e69e1c895af0d4224e62ee33e66a543a14763b0f2e74c1356 languageName: node linkType: hard +"lru-cache@npm:^9.1.1 || ^10.0.0": + version: 10.0.0 + resolution: "lru-cache@npm:10.0.0" + checksum: 18f101675fe283bc09cda0ef1e3cc83781aeb8373b439f086f758d1d91b28730950db785999cd060d3c825a8571c03073e8c14512b6655af2188d623031baf50 + languageName: node + linkType: hard + "lru-queue@npm:^0.1.0": version: 0.1.0 resolution: "lru-queue@npm:0.1.0" @@ -8131,15 +8157,15 @@ __metadata: linkType: hard "minimatch@npm:^8.0.2": - version: 8.0.3 - resolution: "minimatch@npm:8.0.3" + version: 8.0.4 + resolution: "minimatch@npm:8.0.4" dependencies: brace-expansion: ^2.0.1 - checksum: 8957d8105be6729bf1d3af9c410b2a38ffcf3cd17d4ffaf715b2aa4841490aaa82f1ebff785e71b5b97747199ccc61027db597495941cf46243d9a64382e1560 + checksum: 2e46cffb86bacbc524ad45a6426f338920c529dd13f3a732cc2cf7618988ee1aae88df4ca28983285aca9e0f45222019ac2d14ebd17c1edadd2ee12221ab801a languageName: node linkType: hard -"minimist@npm:^1.1.0, minimist@npm:^1.2.0, minimist@npm:^1.2.6": +"minimist@npm:^1.1.0, minimist@npm:^1.2.0, minimist@npm:^1.2.5, minimist@npm:^1.2.6": version: 1.2.8 resolution: "minimist@npm:1.2.8" checksum: 75a6d645fb122dad29c06a7597bddea977258957ed88d7a6df59b5cd3fe4a527e253e9bbf2e783e4b73657f9098b96a5fe96ab8a113655d4109108577ecf85b0 @@ -8206,13 +8232,27 @@ __metadata: languageName: node linkType: hard -"minipass@npm:^4.0.0, minipass@npm:^4.0.2, minipass@npm:^4.2.4": +"minipass@npm:^4.0.0": version: 4.2.5 resolution: "minipass@npm:4.2.5" checksum: 4f9c19af23a5d4a9e7156feefc9110634b178a8cff8f8271af16ec5ebf7e221725a97429952c856f5b17b30c2065ebd24c81722d90c93d2122611d75b952b48f languageName: node linkType: hard +"minipass@npm:^4.2.4": + version: 4.2.8 + resolution: "minipass@npm:4.2.8" + checksum: 7f4914d5295a9a30807cae5227a37a926e6d910c03f315930fde52332cf0575dfbc20295318f91f0baf0e6bb11a6f668e30cde8027dea7a11b9d159867a3c830 + languageName: node + linkType: hard + +"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0": + version: 7.0.2 + resolution: "minipass@npm:7.0.2" + checksum: 46776de732eb7cef2c7404a15fb28c41f5c54a22be50d47b03c605bf21f5c18d61a173c0a20b49a97e7a65f78d887245066410642551e45fffe04e9ac9e325bc + languageName: node + linkType: hard + "minizlib@npm:^2.1.1, minizlib@npm:^2.1.2": version: 2.1.2 resolution: "minizlib@npm:2.1.2" @@ -8400,7 +8440,7 @@ __metadata: languageName: node linkType: hard -"neo-async@npm:^2.6.2": +"neo-async@npm:^2.6.0, neo-async@npm:^2.6.2": version: 2.6.2 resolution: "neo-async@npm:2.6.2" checksum: deac9f8d00eda7b2e5cd1b2549e26e10a0faa70adaa6fdadca701cc55f49ee9018e427f424bac0c790b7c7e2d3068db97f3093f1093975f2acb8f8818b936ed9 @@ -8996,12 +9036,12 @@ __metadata: linkType: hard "path-scurry@npm:^1.6.1": - version: 1.6.3 - resolution: "path-scurry@npm:1.6.3" + version: 1.10.1 + resolution: "path-scurry@npm:1.10.1" dependencies: - lru-cache: ^7.14.1 - minipass: ^4.0.2 - checksum: 814ebd7f8df717e2381dc707ba3a3ddf84d0a4f9d653036c7554cb1fea632d4d78eb17dd5f4c85111b78ba8b8c0a5b59c756645c9d343bdacacda4ba8d1626c2 + lru-cache: ^9.1.1 || ^10.0.0 + minipass: ^5.0.0 || ^6.0.2 || ^7.0.0 + checksum: e2557cff3a8fb8bc07afdd6ab163a92587884f9969b05bbbaf6fe7379348bfb09af9ed292af12ed32398b15fb443e81692047b786d1eeb6d898a51eb17ed7d90 languageName: node linkType: hard @@ -10967,6 +11007,15 @@ __metadata: languageName: node linkType: hard +"uglify-js@npm:^3.1.4": + version: 3.17.4 + resolution: "uglify-js@npm:3.17.4" + bin: + uglifyjs: bin/uglifyjs + checksum: 7b3897df38b6fc7d7d9f4dcd658599d81aa2b1fb0d074829dd4e5290f7318dbca1f4af2f45acb833b95b1fe0ed4698662ab61b87e94328eb4c0a0d3435baf924 + languageName: node + linkType: hard + "unbox-primitive@npm:^1.0.2": version: 1.0.2 resolution: "unbox-primitive@npm:1.0.2" @@ -11593,6 +11642,13 @@ __metadata: languageName: node linkType: hard +"wordwrap@npm:^1.0.0": + version: 1.0.0 + resolution: "wordwrap@npm:1.0.0" + checksum: 2a44b2788165d0a3de71fd517d4880a8e20ea3a82c080ce46e294f0b68b69a2e49cff5f99c600e275c698a90d12c5ea32aff06c311f0db2eb3f1201f3e7b2a04 + languageName: node + linkType: hard + "workerpool@npm:6.2.1": version: 6.2.1 resolution: "workerpool@npm:6.2.1"