Në ekipin tonë ne kemi mjaft detyra të përsëritura kur krijojmë veçori të reja për Sistemin tonë të Menaxhimit të Përmbajtjes. Për shembull, kur krijojmë module të reja për Shërbimin tonë GraphQL, secili prej tyre ndjek të njëjtën strukturë bazë me një skemë, disa zgjidhës dhe teste. Më tej, ekziston një skedar konfigurimi për të njoftuar sistemin se ka një modul të ri. Pra, ne gjithmonë dublikojmë një modul të vjetër, fshijmë pothuajse të gjithë përmbajtjen dhe modifikojmë emrat për t'iu përshtatur modulit tonë të ri.

Pra, ajo që ne vërtet donim ishte të automatizonim të gjitha këto gjëra të mërzitshme, por nuk mund të gjenim ndonjë mësim të mirë se si të krijonim dhe modifikonim skedarët e vjetër me një JavaScript CLI.

Çfarë do të bëjmë?

  • Leximi i hyrjes së përdoruesit në vijën e komandës
  • Leximi dhe analizimi i një skedari JavaScript duke përdorur babel
  • Krijimi i një skedari testimi duke përdorur eksportet e këtij skedari

Vendosja e një projekti të ri

Filloni me krijimin e një projekti duke shtypur komandat e mëposhtme:

mkdir cli-tutorial && cd $_
yarn init -y

Tani kemi një projekt të ri dhe mund të fillojmë me shtimin e disa varësive që do të përdorim.

  • kërkuesi:për ndërveprimin e përdoruesit në terminal
  • babel: analizimi i skedarëve JavaScript për të marrë AST (Pema e sintaksës abstrakte)
yarn add @babel/parser inquirer

Hapni package.json, modifikoni çdo gjë që ju pëlqen për t'iu përshtatur nevojave tuaja dhe shtoni gjithashtu skriptin e fillimit.

{
    ...
    "scripts": {
        "start": "node index.js"
    },
    ...
}

Për më tepër, le të krijojmë një skedar të thjeshtë JavaScript me disa variabla/funksione/klasa të eksportuara dhe le ta quajmë atë dummy.js:

const sum1 = 7
const firstname = 'John'
export const add = sum2 => sum1 + sum2
export const fullName = firstname + ' Doe'
export class Vector {
  constructor(x, y) {
    this.x = x
    this.y = y
  }
length() {
    return Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2))
  }
}

Leximi i emrit të skedarit nga hyrja e përdoruesit

Tani duam që përdoruesi të zgjedhë një skedar nga drejtoria aktuale e punës. Për ta bërë këtë, nevojiten tre hapa:

  1. Merr të gjithë skedarët që përfundojnë me .js por jo .test.js nga drejtoria aktuale.
  2. Shfaqi këta skedarë në një listë në terminal duke përdorur kërkuesit.
  3. Prisni që përdoruesi të zgjedhë një skedar.

Pra, ne krijojmë një index.js dhe ngjitim rreshtat e mëposhtëm:

const fs = require('fs')
const inquirer = require('inquirer')
const run = async () => {
    const directoryFiles = fs
        .readdirSync(process.cwd())
        .filter(file => file.endsWith('.js') && 
            !file.endsWith('.test.js'))
    const { filename } = await inquirer.prompt({
        type: 'list',
        name: 'filename',
        choices: directoryFiles,
    })
}
run()

Leximi i përmbajtjes së skedarit

Për të marrë përmbajtjen e skedarit, ne duhet ta lexojmë atë duke përdorur modulin fs i cili është mjaft themelor. Atëherë mund të përdorim modulin e analizës së babelit për të marrë AST të kodit.

...
const { parse } = require('@babel/parser')
const run = async () => {
    ...
    const content = fs.readFileSync(filename, 'utf-8')
    const ast = parse(content, {
         sourceType: 'module',
    })
}

Vendosja e sourceType në modul e bën të ditur analizuesin se lexon një skedar ES6 që përdor deklarata importi dhe eksporti.

Ju gjithashtu mund të vizitoni http://www.astexplorer.com dhe të ngjisni dummy.js tonë për të parë se si duket AST. Ka disa veti të tipit VariableDeclaration dhe disa veti të tipit ExportNamedDeclaration.

Në rastin tonë të përdorimit, na duhen vetëm të gjithë emrat e atyre ExportNamedDeclarations, kështu që ne e shtojmë këtë funksion në index.js:

function getExports(body) {
  const namedExports = body
    .filter(item => item.type === 'ExportNamedDeclaration')
    .map(item => item.declaration)
    .reduce((total, current) => {
      if (current.id) {
        return [...total, current.id.name]
      } else if (current.declarations) {
        return [
          ...total,
          ...current.declarations.map(declaration => declaration.id.name),
        ]
      }
    }, [])
  return namedExports
}

Funksioni i reduktimit kujdeset për strukturën e ndryshme të eksportit të parë në krahasim me dy të tjerët.

Krijimi i një skedari testimi

Për të gjeneruar skedarë të rinj, le të krijojmë create-test-file.js i cili do të përmbajë modelin tonë të testit:

module.exports = {
  createTestFile: ({ filename, imports }) => {
    return `/* eslint-env jest */
import { ${imports.join(', ')} } from '${filename}'
describe('${filename}', () => {
    ${imports
      .map(i => {
        return `test('${i}', () => {
        expect(true).toBeTruthy()
    })`
      })
      .join('\r\n \r\n \t')}
}) 
`
  },
}

Duke përdorur një template-literal ne thjesht mund të plotësojmë variablat tona. Në fillim do të importojmë të gjitha pronat e eksportuara nga skedari origjinal. Më pas krijojmë një funksion testimi për secilën nga këto veti.

Kthehu te index.js ne tani mund të përdorim këtë shabllon:

const { createTestFile } = require('./create-test-file')
const run = async () => {
    ...
    const exports = getExports(ast.program.body)
    const testContent = createTestFile(
        { imports: exports, filename }
    )
}

Gjëja e fundit që duhet të bëjmë është të gjenerojmë një emër skedari për testin, i cili në rastin tonë do të jetë dummy.test.js. Pas kësaj, ne thjesht mund ta vendosim përmbajtjen në skedar.

const run = async () => {
    ...    
    const testFilename = createTestFilename(filename)
    fs.writeFileSync(testFilename, testContent)
}
function createTestFilename(originalName) {
    const parts = originalName.split('.')
    return parts.slice(0, -1).join('.') 
        + '.test.' + parts[parts.length - 1]
}

Tani le të ekzekutojmë CLI-në tonë duke shtypur fillin fillnë terminal.

Bëjeni CLI-në të disponueshme globalisht

Për të qenë në gjendje të ekzekutojmë skriptin tonë nga kudo në terminal, duhet të shtojmë sa vijon në package.json:

{
    ...
    "bin": {
         "cli-tutorial": "./index.js"
     },
}

Ne gjithashtu duhet të shtojmë rreshtin e mëposhtëm në krye të index.js:

#!/usr/bin/env node

Tani le të instalojmë globalisht CLI duke ekzekutuar npm i -g

Depoja e GitHub