paint-brush
একটি টেমপ্লেট, পরীক্ষা এবং প্রকাশনা সহ টাইপস্ক্রিপ্টে কীভাবে আপনার ESLint প্লাগইন তৈরি করবেনদ্বারা@antonkrylov322
1,945 পড়া
1,945 পড়া

একটি টেমপ্লেট, পরীক্ষা এবং প্রকাশনা সহ টাইপস্ক্রিপ্টে কীভাবে আপনার ESLint প্লাগইন তৈরি করবেন

দ্বারা Anton Krylov13m2023/03/20
Read on Terminal Reader
Read this story w/o Javascript

অতিদীর্ঘ; পড়তে

পরীক্ষা এবং টেমপ্লেট সহ টাইপস্ক্রিপ্ট ব্যবহার করে নিজেই এসলিন্ট প্লাগইন লিখুন। আপনি AST সম্পর্কে আরও জানতে পারবেন এবং টাইপসক্রিপ্টে কীভাবে এটি মোকাবেলা করতে হবে (হ্যাঁ যদি আপনি এটি ভালভাবে জানেন তবে এটি সহজ)। এছাড়াও আপনি এই নিবন্ধের চিন্তার ইতিহাস বোঝার জন্য আমার PR এবং প্রতিশ্রুতির ইতিহাসের মধ্য দিয়ে যেতে পারেন :)
featured image - একটি টেমপ্লেট, পরীক্ষা এবং প্রকাশনা সহ টাইপস্ক্রিপ্টে কীভাবে আপনার ESLint প্লাগইন তৈরি করবেন
Anton Krylov HackerNoon profile picture
0-item

সুচিপত্র

  1. একটি টেমপ্লেট ব্যবহার করে রেপো শুরু করুন
  2. একটি টেমপ্লেটের প্রাথমিক গঠন
  3. একটি টেমপ্লেট থেকে স্ক্রিপ্ট ব্যবহার করে নিয়ম যোগ করা
  4. Eslint প্লাগইনের জন্য পরীক্ষা লিখুন
  5. Eslint নিয়ম লিখুন
  6. ছোট AST ব্যাখ্যা
  7. চূড়ান্ত বৈকল্পিক
  8. স্ক্রিপ্ট ব্যবহার করে ডক্স আপডেট করা হচ্ছে
  9. প্লাগইন প্রকাশনা
  10. আপনার অ্যাপ্লিকেশনের সাথে এটি সংযুক্ত করুন

পটভূমি

আমি ধাপে ধাপে ব্যাখ্যা সহ Reatom সংগ্রহস্থলে আমার পিআর-এর উপর ভিত্তি করে একটি টিউটোরিয়াল লেখার চেষ্টা করব: https://github.com/artalar/Reatom/pull/488


আপনি যদি আরও জানতে চান, আপনি https://github.com/artalar/reatom/issues/487 সমস্যাটি পড়তে পারেন।


একটু প্রসঙ্গ যোগ করার জন্য, Reatom হল একটি রাষ্ট্রীয় ব্যবস্থাপনা লাইব্রেরি। পরমাণু হল Reatom-এর একটি ধারণা, প্রতিক্রিয়ার জন্য একটি রাষ্ট্রীয় ব্যবস্থাপনা লাইব্রেরি।

ESLint প্লাগইন এবং নিয়ম কি কি?

ESLint প্লাগইন হল এক্সটেনশন যা নির্দিষ্ট কোডিং মান প্রয়োগ করতে মূল ESLint প্যাকেজের সাথে কাজ করে। প্লাগইনগুলিতে একটি rules ফোল্ডার রয়েছে, যা এই মানগুলি কার্যকর করার জন্য পৃথক নিয়মগুলি সংজ্ঞায়িত করে৷


প্রতিটি rule মডিউলের একটি meta বৈশিষ্ট্য রয়েছে যা নিয়ম বর্ণনা করে এবং একটি create সম্পত্তি যা নিয়মের আচরণকে সংজ্ঞায়িত করে।


create ফাংশনটি একটি context আর্গুমেন্ট নেয়, যা চেক করা কোডের সাথে ইন্টারঅ্যাক্ট করতে ব্যবহৃত হয় এবং আপনি এটিকে আপনার নিয়মের যুক্তি নির্ধারণ করতে ব্যবহার করতে পারেন, যেমন আপনার লাইব্রেরির জন্য কঠোর নামকরণের নিয়মাবলী প্রয়োজন।

আসুন কোডের মধ্যে ডুব দেই

রেপো আরম্ভ করুন

একটি নতুন টাইপস্ক্রিপ্ট এসলিন্ট প্রকল্প তৈরি করা হচ্ছে

 npx degit https://github.com/pivaszbs/typescript-template-eslint-plugin reatom-eslint-plugin


তারপরে, নতুন প্রকল্প ডিরেক্টরিতে নেভিগেট করুন এবং এর সাথে নির্ভরতাগুলি ইনস্টল করুন:

 cd reatom-eslint-plugin && npm i


আমি একটি ভাল ছেলে হতে চাই, তাই আমি git init.

 git init && git add . && git commit -m "init"


এরপর, package.json ফাইলটি খুলুন এবং name ক্ষেত্রটি সনাক্ত করুন। এই ক্ষেত্রটি অপরিহার্য কারণ এটি ব্যবহার করার সময় এটি আপনার প্লাগইনটির জন্য প্রধান এন্ট্রি পয়েন্ট হবে। আপনি এটিকে নিম্নলিখিতগুলিতে পরিবর্তন করতে পারেন:

 "name": "eslint-plugin-reatom"


বিকল্পভাবে, আপনি স্কোপড প্যাকেজ নামকরণ কনভেনশন ব্যবহার করতে পারেন:

 "name": "@reatom/eslint-plugin"

প্রাথমিক কাঠামো

 - scripts // some automation to concentrate on writing rules - docs - rules // here will be generated by npm run add-rule files - src - configs recommended.ts // generated config - rules // all your rules index.ts // Connection point to your plugin, autogenerated by scripts/lib/update-lib-index.ts


সাধারণ সূচীতে, ফাইলগুলি স্ক্রিপ্ট দ্বারা তৈরি করা হবে, তাই আপনাকে এটি নিয়ে চিন্তা করতে হবে না 😀

 /* DON'T EDIT THIS FILE. This is generated by 'scripts/lib/update-lib-index.ts' */ import { recommended } from './configs/recommended'; import exampleRule from './rules/example-rule' export const configs = { recommended }; export const rules = { 'example-rule': exampleRule };

নিয়ম যোগ করা এবং ডক্স আপডেট করা

এই সংগ্রহস্থলে, আপনি নিয়ম যোগ করার এবং নথি আপডেট করার জন্য কিছু সুবিধাজনক স্ক্রিপ্ট পাবেন। একটি নতুন নিয়ম যোগ করতে, আপনি নিম্নলিখিত কমান্ড ব্যবহার করতে পারেন:

 npm run add-rule atom-rule suggestion


এটি নতুন নিয়মের জন্য তিনটি বিভাগ তৈরি করবে: ডকুমেন্টেশন, পরীক্ষা এবং প্রকৃত কোড। আমরা আপাতত ডকুমেন্টেশন বিভাগটি এড়িয়ে যেতে পারি এবং শেষ দুটিতে ফোকাস করতে পারি।

পরীক্ষা লিখুন

একজন TDD (পরীক্ষা-চালিত বিকাশ) উত্সাহী হিসাবে, আমরা tests/atom-rule.ts ফাইলে কিছু সহজ পরীক্ষা তৈরি করে শুরু করব:

 // tests/atom-rule.ts tester.run('atom-rule', atomRule, { valid: [ { code: 'const countAtom = atom(0, "countAtom");' }, ], invalid: [ { code: `const countAtom = atom(0);`, errors: [{ message: 'atom name is not defined' }] }, { code: 'const countAtom = atom(0, "count");', errors: [{ message: 'atom name is defined bad'}] }, ] });


আপনি এখন পরীক্ষা চালালে, তারা ব্যর্থ হবে কারণ আমরা এখনও atomRule প্রয়োগ করিনি।

নিয়ম লেখা

atomRule হল যেখানে আমরা নিয়মের আচরণকে সংজ্ঞায়িত করি। এখানে একটি সহজ বাস্তবায়ন:

 import { Rule } from "eslint"; const rule: Rule.RuleModule = { meta: { docs: { description: "Add name for every atom call", // simply describe your rule recommended: true, // if it's recommended, then npm run update will add it to recommmended config }, type: "suggestion" }, create: function (context: Rule.RuleContext): Rule.RuleListener { return { VariableDeclaration: node => { // listener for declaration, here we can specifiy more specific selector node.declarations.forEach(d => { if (d.init?.type !== 'CallExpression') return; if (d.init.callee.type !== 'Identifier') return; if (d.init.callee.name !== 'atom') return; if (d.id.type !== 'Identifier') return; // just guard everything that we don't need if (d.init.arguments.length <= 1) { // show error in user code context.report({ message: `atom name is not defined`, // here we can pass what will be underlined by red/yellow line node, }) } if (d.init.arguments[1]?.type !== 'Literal') return; // just another guard if (d.init.arguments[1].value !== d.id.name) { context.report({ message: `atom name is defined bad`, node }) } }) } }; }, }; export default rule;


এটি একটি সাধারণ বৈকল্পিক, কিন্তু এখানে, আমরা সহজেই বুঝতে পারি কি ঘটছে।


আপনার কোডের AST গঠন সম্পর্কে আরও ভালোভাবে বোঝার জন্য, আপনি https://astexplorer.net/ ব্যবহার করতে পারেন অথবা কেবল console.log পার্স করা নোড ব্যবহার করতে পারেন।

এএসটি টাইপিং ভালো বোঝার জন্য একটি ছোট ব্যাখ্যা

এখানে একটি ছোট উদাহরণে প্রতিটি শনাক্তকারীর একটি ছোট বিবরণ রয়েছে:

const kek = atom('kek')


  1. Identifier : একটি টাইপস্ক্রিপ্ট ইন্টারফেস যা একটি AST-তে একটি শনাক্তকারী নোডকে প্রতিনিধিত্ব করে।

    1. const kek = পরমাণু ('kek'), kek এবং পরমাণু হল শনাক্তকারী নোড।


  2. Literal : একটি টাইপস্ক্রিপ্ট ইন্টারফেস যা একটি AST-তে একটি আক্ষরিক মান (স্ট্রিং, সংখ্যা, বুলিয়ান, ইত্যাদি) নোডকে প্রতিনিধিত্ব করে। const kek = atom(' kek '), 'kek' একটি আক্ষরিক।


  3. CallExpression : একটি টাইপস্ক্রিপ্ট ইন্টারফেস যা একটি বিমূর্ত সিনট্যাক্স ট্রি (AST) এ একটি ফাংশন কল এক্সপ্রেশন নোডকে উপস্থাপন করে।


    1. আমাদের উদাহরণে, atom('kek') হল একটি CallExpression, যার মধ্যে রয়েছে পরমাণু - শনাক্তকারী এবং কেক - আক্ষরিক।


  4. VariableDeclarator : একটি টাইপস্ক্রিপ্ট ইন্টারফেস যা একটি AST-তে একটি পরিবর্তনশীল ঘোষণাকারী নোডকে প্রতিনিধিত্ব করে


    1. আমাদের উদাহরণে, const ব্যতীত সম্পূর্ণ অভিব্যক্তি হল VariableDeclarator kek = atom('kek')


  5. Node : একটি টাইপস্ক্রিপ্ট ইন্টারফেস যা একটি জেনেরিক AST নোডকে উপস্থাপন করে।


অথবা শুধুমাত্র astexplorer ব্যবহার করে

চূড়ান্ত বৈকল্পিক

চূড়ান্ত পরীক্ষা

 tester.run('atom-rule', rule, { valid: [ { code: ` import { atom } from '@reatom/framework' const countAtom = atom(0, "countAtom"); ` }, { code: `const countAtom = atom(0);`, }, { code: 'const countAtom = atom(0, "count");', }, ], invalid: [ { code: ` import { atom } from '@reatom/framework' const countAtom = atom(0); `, errors: [{ message: 'atom "countAtom" should has a name inside atom() call', }], output: ` import { atom } from '@reatom/framework' const countAtom = atom(0, "countAtom"); `, }, { code: ` import { atom } from '@reatom/framework' const countAtom = atom(0, "count"); `, errors: [{ message: `atom "countAtom" should be named as it's variable name, rename it to "countAtom"` }], output: ` import { atom } from '@reatom/framework' const countAtom = atom(0, "countAtom"); `, }, ] });


পরীক্ষা থেকে, আমরা বুঝতে পারি যে আমাদের নিয়ম ব্যবহার করে সোর্স কোড পরিবর্তন করতে হবে।

কিভাবে আপনার নিয়ম স্থির করা যায়?

প্রসঙ্গ প্রতিবেদনে একটি সহজ লাইন যোগ করুন।

 fix: fixer => fixer.replaceText(node, replaceString)


নোড - একটি প্রকৃত নোড বা চিহ্নের পরিসর হতে পারে যা আপনি প্রতিস্থাপন করতে চান।


রিপ্লেস স্ট্রিং - আপনি কোন কোডটি দেখতে চান।


আপনার নিয়ম মেটা ট্যাগের জন্য fixable : 'code' বা fixable : 'whitespace' যোগ করতে ভুলবেন না।


আপনি যদি eslint এর সাথে কীভাবে এটি ঠিক করবেন তার সাথে পরিচিত না হন তবে আপনার বিদ্যমান প্রকল্পে চেষ্টা করুন।

 eslint --fix ./src

নিজেই কোড

 import { Rule } from "eslint"; import { CallExpression, Identifier, Literal, VariableDeclarator, Node } from 'estree'; import { isIdentifier, isLiteral } from "../lib"; type AtomCallExpression = CallExpression & { callee: Identifier, arguments: [Literal] | [Literal, Literal] } type AtomVariableDeclarator = VariableDeclarator & { id: Identifier, init: AtomCallExpression } const noname = (atomName: string) => `atom "${atomName}" should has a name inside atom() call`; const invalidName = (atomName: string) => `atom "${atomName}" should be named as it's variable name, rename it to "${atomName}"`; export const atomRule: Rule.RuleModule = { meta: { type: 'suggestion', docs: { recommended: true, description: "Add name for every atom call" }, fixable: 'code' }, create: function (context: Rule.RuleContext): Rule.RuleListener { let importedFromReatom = false; return { ImportSpecifier(node) { const imported = node.imported.name; // @ts-ignore const from = node.parent.source.value; if (from.startsWith('@reatom') && imported === 'atom') { importedFromReatom = true; } }, VariableDeclarator: d => { if (!isAtomVariableDeclarator(d) || !importedFromReatom) return; if (d.init.arguments.length === 1) { reportUndefinedAtomName(context, d); } else if (isLiteral(d.init.arguments[1]) && d.init.arguments[1].value !== d.id.name) { reportBadAtomName(context, d); } } }; } } function isAtomCallExpression(node?: Node | null): node is AtomCallExpression { return node?.type === 'CallExpression' && node.callee?.type === 'Identifier' && node.callee.name === 'atom'; } function isAtomVariableDeclarator(node: VariableDeclarator): node is AtomVariableDeclarator { return isAtomCallExpression(node.init) && isIdentifier(node.id); } function reportUndefinedAtomName(context: Rule.RuleContext, d: AtomVariableDeclarator) { context.report({ message: noname(d.id.name), node: d, fix: fixer => fixer.insertTextAfter(d.init.arguments[0], `, "${d.id.name}"`) }); } function reportBadAtomName(context: Rule.RuleContext, d: AtomVariableDeclarator) { context.report({ message: invalidName(d.id.name), node: d, fix: fixer => fixer.replaceText(d.init.arguments[1], `"${d.id.name}"`) }); }


আপনি দেখতে পাচ্ছেন, এতে আরও ভাল ত্রুটি রয়েছে, টাইপ গার্ড রয়েছে এবং আমদানি পরীক্ষা অন্তর্ভুক্ত রয়েছে। এবং, অবশ্যই, আমি নিয়ম সংশোধনযোগ্য.

ডক্স আপডেট করা হচ্ছে

নথি আপডেট করতে, আপনি নিম্নলিখিত কমান্ড ব্যবহার করতে পারেন:

 npm run update


এই কমান্ডটি README.md আপডেট করবে এবং প্রতিটি নিয়মের জন্য ডক্স আপডেট করবে (তবে আপনাকে ডক্স/{rule} ফাইলে প্রতিটি নিয়ম সম্পর্কে কিছুটা লিখতে হবে)।


এছাড়াও, যেমন আমি বলেছি, আপনাকে সূচী ফাইল সম্পর্কে চিন্তা করতে হবে না।

ধাপ প্রকাশ করুন

সংস্করণটি আপনার package.json-এ রয়েছে তা নিশ্চিত করুন।

 "version": "1.0.0"


টার্ম লিখুন যদি এটি 1.0.0 না হয়।

 npm version 1.0.0


তারপর শুধু রুটে লিখুন।

 npm publish


আপনার সংজ্ঞায়িত প্যাকেজের নাম দিয়ে সবকিছু তৈরি এবং প্রকাশ করা হবে।

আপনার অ্যাপ্লিকেশনের সাথে এটি সংযুক্ত করুন

আমি আমার প্যাকেজ নাম.

 @reatom/eslint-plugin


সুতরাং, আমি এটি ইনস্টল করতে হবে.

 npm i @reatom/eslint-plugin


এবং আমার .eslintrc কনফিগারেশন যোগ করুন।

 module.exports = { plugins: [ "@reatom" ], // use all rules extends: [ "plugin:@reatom/recommended" ], // or pick some rules: { '@reatom/atom-rule': 'error', // aditional rules, you can see it in PR '@reatom/action-rule': 'error', '@reatom/reatom-prefix-rule': 'error' } }


এবং সবকিছুই ঠিক কাজ করে (শুধু reatom-eslint-plugin এর জন্য আপনাকে সর্বত্র “@reatom" এর পরিবর্তে “reatom” লিখতে হবে)।

উপসংহার

এই টিউটোরিয়ালে, আমরা Reatom স্টেট ম্যানেজমেন্ট লাইব্রেরির জন্য একটি ESLint প্লাগইন তৈরি করার প্রক্রিয়ার মধ্য দিয়ে হেঁটেছি। আমরা কভার করি:


  1. টাইপস্ক্রিপ্টে কীভাবে একটি এসলিন্ট প্লাগইন লিখবেন।
  2. কিভাবে পরীক্ষা দিয়ে এটি আবরণ.
  3. --fix বিকল্পের সাথে এটিকে কীভাবে কাজ করা যায়।
  4. কিভাবে আমার টেমপ্লেট ব্যবহার করতে হয়.
  5. কিভাবে eslint প্লাগইন প্রকাশ করবেন।
  6. eslint এর সাথে আপনার বিদ্যমান সংগ্রহস্থলে এটি কীভাবে যুক্ত করবেন


আরও শেখার এবং অন্বেষণের জন্য সম্পদ

  1. https://github.com/pivaszbs/typescript-template-eslint-plugin
  2. https://astexplorer.net/
  3. https://github.com/artalar/reatom/pull/488/files
  4. https://eslint.org/docs/latest/extend/plugins
  5. https://www.reatom.dev/
  6. https://github.com/artalar/reatom
  7. https://docs.npmjs.com/about-semantic-versioning


আনন্দ কর :)