Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
直接コマンドでは確認用 Prompt が省略されます。実行前にソースを確認してください。
npx skills add https://github.com/Objective-Arts/lens-dist --skill functionalコマンドは1行のまま表示されます。コピー前に横へスクロールして全体を確認してください。
ローカルで確認しますか?SkillsMP が現在取得できるファイルをダウンロードできます。
SKILL.md を表示中
SOC 職業分類に基づく
| name | functional |
| description | Functional JS elegance |
Applying the design philosophy of Jeremy Ashkenas (Backbone.js, Underscore.js, CoffeeScript) to JavaScript library and utility development. Use this when writing JavaScript utilities, designing APIs, building small libraries, or refactoring code toward functional elegance. Auto-invokes for .js files involving utility functions, library design, collection manipulation, or API surface design. Not for framework-heavy code (React, Angular), build tooling, or Node.js server infrastructure.
Readable over clever. Code is read far more than written. Optimize for the reader who encounters your code six months from now.
Small, focused functions. Each function does one thing. Name it for what it does. If the name is awkward, the function does too much.
Functional foundations. Prefer map, filter, reduce over loops. Treat data as immutable. Return new values rather than mutating.
Minimal API surface. The best library is the smallest one that solves the problem. Every public method is a promise to maintain.
Convention over configuration. Establish sensible defaults. Let users override when needed, not require configuration upfront.
// Transform collections, not items
const getActiveUserEmails = (users) =>
users
.filter(user => user.active)
.map(user => user.email);
// Not this - imperative, mutable
const getActiveUserEmails = (users) => {
const emails = [];
for (let i = 0; i < users.length; i++) {
if (users[i].active) {
emails.push(users[i].email);
}
}
return emails;
};
// Loose coupling through events
class Model {
constructor() {
this._events = {};
this._attributes = {};
}
set(key, value) {
const prev = this._attributes[key];
this._attributes[key] = value;
if (prev !== value) {
this.trigger('change', key, value, prev);
this.trigger(`change:${key}`, value, prev);
}
return this;
}
on(event, callback) {
(this._events[event] ||= []).push(callback);
return this;
}
trigger(event, ...args) {
(this._events[event] || []).forEach(cb => cb(...args));
return this;
}
}
// Everything returns a value
const classify = (score) =>
score >= 90 ? 'A' :
score >= 80 ? 'B' :
score >= 70 ? 'C' :
score >= 60 ? 'D' : 'F';
// Destructuring for clarity
const formatUser = ({ name, email, role = 'member' }) =>
`${name} <${email}> (${role})`;
// Default parameters over conditionals
const paginate = (items, page = 1, perPage = 10) =>
items.slice((page - 1) * perPage, page * perPage);
class Query {
constructor(data) {
this._data = data;
this._filters = [];
this._sort = null;
this._limit = null;
}
where(predicate) {
this._filters.push(predicate);
return this; // Always return this for chaining
}
sortBy(key, direction = 'asc') {
this._sort = { key, direction };
return this;
}
limit(n) {
this._limit = n;
return this;
}
value() {
let result = this._data;
for (const filter of this._filters) {
result = result.filter(filter);
}
if (this._sort) {
const { key, direction } = .;
mult = direction === ? : -;
result = [...result].( a[key] > b[key] ? mult : -mult);
}
(.) {
result = result.(, .);
}
result;
}
}
topUsers = (users)
.( u.)
.( u. > )
.(, )
.()
.();
// Good: defaults that work, options that customize
const fetch = (url, options = {}) => {
const config = {
method: 'GET',
headers: { 'Content-Type': 'application/json' },
timeout: 5000,
retries: 3,
...options
};
// ...
};
// Most calls are simple
fetch('/api/users');
// Complex when needed
fetch('/api/users', { method: 'POST', body: data });
// Predicates start with is/has/can
const isEmpty = (arr) => arr.length === 0;
const hasChildren = (node) => node.children?.length > 0;
const canEdit = (user, doc) => doc.ownerId === user.id;
// Transformers are verbs or "to" + noun
const slugify = (str) => str.toLowerCase().replace(/\s+/g, '-');
const toArray = (value) => Array.isArray(value) ? value : [value];
// Getters match property names
const getName = (obj) => obj.name;
const getById = (id) => (arr) => arr.find(x => x.id === id);
// Pipe: left-to-right composition
const pipe = (...fns) => (x) => fns.reduce((v, f) => f(v), x);
// Usage
const processUser = pipe(
validateEmail,
normalizePhone,
hashPassword,
saveToDatabase
);
// Compose: right-to-left (mathematical order)
const compose = (...fns) => (x) => fns.reduceRight((v, f) => f(v), x);
const memoize = (fn) => {
const cache = new Map();
return (...args) => {
const key = JSON.stringify(args);
if (!cache.has(key)) {
cache.set(key, fn(...args));
}
return cache.get(key);
};
};
const debounce = (fn, wait) => {
let timeout;
return (...args) => {
clearTimeout(timeout);
timeout = setTimeout(() => fn(...args), wait);
};
};
const throttle = (fn, wait) => {
let lastCall = 0;
return (...args) => {
const now = Date.now();
if (now - lastCall >= wait) {
lastCall = now;
fn(...args);
}
};
};
const partial = (fn, ...presetArgs) =>
(...laterArgs) => fn(...presetArgs, ...laterArgs);
// Usage
const greet = (greeting, name) => `${greeting}, ${name}!`;
const sayHello = partial(greet, 'Hello');
sayHello('World'); // "Hello, World!"
When reviewing JavaScript utilities and libraries:
thismap/filter/reduce over imperative loopsfind/some/every when appropriatethis or arguments needed?.) and nullish coalescing (??)// Bad: AbstractFactoryProviderManager
class UserServiceFactoryProvider {
createUserServiceFactory() {
return new UserServiceFactory();
}
}
// Good: just a function
const createUser = (data) => ({ id: uuid(), ...data, createdAt: Date.now() });
// Bad: abstracting on first use
const makeAdder = (x) => (y) => x + y;
const add5 = makeAdder(5);
add5(3); // Just use 5 + 3
// Good: abstract when you see the pattern repeated
// (wait until you need it in 3+ places)
// Bad: over-configured
fetch({ url: '/users', method: 'GET', format: 'json' });
// Good: simple API, options when needed
fetch('/users');
fetch('/users', { method: 'POST' });
Use for:
Skip for: