Tuesday

A Simple Agentic Coding Workflow for Java

AI coding agents can already write classes, add tests, refactor code, and fix bugs. But using an AI agent for coding is not the same as having an agentic development workflow.

If one agent receives a large task and does everything inside the same context, it is still mostly:

prompt → generate code → hope it is correct

A more structured approach is to separate planning, implementation, review, and verification.

This is the approach I tried in ModelMatrix4J , a Java project used to experiment with agent-first development.

The basic workflow looks like this:

Architect + Test Planner
        ↓
    Orchestrator
        ↓
    Implementer
        ↓
Reviewer + Adversarial Reviewer
        ↓
    mvnw verify

The important point is that these are not just role names written inside one prompt. They are separate Codex agents with different responsibilities and permissions.


What Does Agent-First Mean?

Agent-first means the repository is prepared for agents to work inside it safely.

A fresh coding agent should be able to answer a few basic questions:

What am I allowed to change?

What should I not change?

What must happen before my task starts?

Who reviews my work?

How is completion verified?

If these answers only exist inside a developer's head, every new agent session needs another large prompt.

A better approach is to keep the important boundaries inside the repository.


Separate Agents for Separate Jobs

ModelMatrix4J defines project-level Codex agents under:

.codex/agents/

The current setup contains:

architect
test-planner
implementer
reviewer
adversarial-reviewer

Each agent has one clear responsibility.

Architect

The architect looks at design, module boundaries, dependency direction, and public API pressure.

It is read-only. It can recommend a design, but it cannot start changing production code.

Test Planner

The test planner looks at acceptance criteria, deterministic tests, failure cases, and isolation.

It is also read-only.

Implementer

The implementer receives a specific writable scope and makes the actual changes.

Reviewer

The reviewer checks correctness, architecture, scope, and test coverage after implementation.

Adversarial Reviewer

The adversarial reviewer looks for things that are easier to miss:

edge cases
failure paths
bad assumptions
scope leaks
missing negative tests
false completion claims

Review agents stay read-only and independent from the implementer.


Permissions Are Part of the Design

Different responsibilities should also have different permissions.

A simplified architect configuration looks like this:

name = "architect"
sandbox_mode = "read-only"
approval_policy = "never"

The implementer is different:

name = "implementer"
sandbox_mode = "workspace-write"

This is useful because planning and reviewing do not automatically come with permission to edit the repository.

The agent role is not only a prompt. It also defines what kind of work the agent is allowed to perform.


Keep AGENTS.md Small

Repository instructions can easily become another large documentation system. That should be avoided.

The root AGENTS.md should mainly contain the rules every agent needs.

For example:

Work only inside the approved milestone.

Change only the assigned files or paths.

Do not silently change public/shared APIs.

Do not implement future functionality early.

Read the nearest module-level AGENTS.md before editing a module.

Run the canonical verification command before completion.

More specific rules can live closer to the module.

For example:

modelmatrix-core/AGENTS.md
modelmatrix-junit/AGENTS.md

The core module can say:

Keep production code JDK-only.

Do not introduce Spring, Spring AI, or JUnit into production core code.

Keep default tests deterministic and offline.

The JUnit module can define its own dependency and isolation rules.

This keeps instructions local instead of turning the root file into a large manual.


Use Skills for Repeated Workflows

Agent roles answer:

Who should do this?

Skills answer:

How should this type of work be done?

The project keeps a small set of repository skills:

.agents/skills/
  modelmatrix-milestone/
  modelmatrix-review/
  modelmatrix-verify/

The milestone skill defines the normal development flow.

  1. Architect and test planner inspect the task.
  2. The orchestrator reconciles their recommendations.
  3. An implementer receives a bounded writable task.
  4. Independent reviewers inspect the integrated changes.
  5. The repository is verified.

The important point is not the exact skill names.

The useful part is making repeated engineering workflows reusable instead of explaining them again in every large prompt.


Give Implementers a Bounded Task

A coding agent should not receive an instruction like:

Implement the next milestone.

That leaves too much room for interpretation.

A better delegation is closer to this:

Objective:
Implement the minimal scenario contract.

Allowed files:
modelmatrix-core/src/main/java/.../Scenario.java
modelmatrix-core/src/test/java/.../ScenarioTest.java

Forbidden:
pom.xml
modelmatrix-junit/**
unrelated public contracts

Prerequisites:
architecture review completed

Acceptance:
focused tests pass
full Maven verification passes

Now the agent knows both sides of the task:

what to do
and
where to stop

This is one of the most useful ideas in agentic coding.

Good delegation is not only about giving agents enough context. It is also about giving them a clear boundary.


Parallel Agents Without Conflicts

Multiple agents can work in parallel, but parallel writing needs more control than parallel reading.

The rule is:

Parallel writable tasks
    → separate Git worktrees
    → non-overlapping writable scopes

Overlapping writable tasks
    → run sequentially

Separate worktrees give filesystem isolation.

But filesystem isolation is not architectural permission.

An agent working in another worktree still cannot decide to change a shared API, another module, or a common contract unless that change is part of its delegated scope.

Shared contract changes go back through the orchestrator.

This keeps parallelism useful without allowing several agents to independently redesign the same part of the system.


Independent Review Comes Before Done

The implementer does not decide alone that the work is complete.

After implementation, separate read-only reviewers inspect the integrated diff.

The normal reviewer checks things like:

correctness
architecture boundaries
scope
public API changes
test coverage
dependency direction

The adversarial reviewer asks different questions:

What happens on failure?

What assumption is not tested?

Can this bypass a repository rule?

Is the result deterministic?

Could this accidentally affect another module?

Are we calling something complete only because the happy path passes?

Using two different review perspectives gives better feedback than asking the implementation agent to review its own work.


Keep Different Sources of Truth Separate

One common problem in AI-assisted projects is duplicated documentation. The same rule appears in several files, and eventually they disagree.

A simpler structure is:

.codex/agents/
    → who does the work

.agents/skills/
    → how repeated workflows run

AGENTS.md
    → repository rules

docs/PRODUCT_SPEC.md
    → what the product should do

docs/ARCHITECTURE.md
    → architecture and dependency boundaries

docs/ROADMAP.md
    → what is allowed to be implemented now

Each file has a different job.

This also makes it easier for an agent to find the correct information without loading every document in the repository.


Use One Clear Verification Command

An agentic workflow needs an executable definition of done.

For this project, the canonical command is:

./mvnw -B verify

The same command is used as the main local and CI verification path.

Important architecture rules can also become build rules when they can be checked mechanically.

For example, the core module prevents dependencies such as Spring, Spring AI, and provider SDKs from entering the core dependency graph.

This creates an important distinction:

Documentation:
"This dependency should not be here."

Build rule:
"This dependency cannot be here without failing verification."

For agentic coding, executable boundaries become more valuable as the codebase grows.


A Small Setup Is Enough

Agentic coding does not require ten agents, a workflow engine, or a large amount of AI-specific infrastructure.

A useful starting point can be:

Architect
    ↓
Implementer
    ↓
Reviewer
    ↓
Build + Tests

More specialization can be added when there is a real reason for it.

The important parts are:

  • clear agent responsibilities
  • read-only planning and review where possible
  • bounded writable scopes
  • small repository instructions
  • safe parallel work
  • independent review
  • executable verification

The Main Idea

The goal of agentic coding is not to run as many agents as possible.

The goal is controlled delegation.

A good agent should be able to enter the repository, understand its task, respect the boundaries, make a focused change, hand the result to another agent for review, and finish with real verification.

In simple form:

plan
  ↓
delegate
  ↓
implement
  ↓
review
  ↓
verify

That is the agent-first development approach used in ModelMatrix4J .

Sunday

Specs as Boundaries: A Lightweight SDD Workflow for AI Coding Agents

AI coding agents are no longer just autocomplete tools. They can create project structures, implement features, write tests, refactor code, and explain their decisions.

That is exactly why they need better boundaries.

When an agent is weak, the problem is getting it to produce useful code. When an agent is strong, the problem becomes controlling what it changes, what it ignores, and how it stays aligned with the product.

If we only prompt the agent directly, the project can drift.

A single prompt may be clear in your head, but the agent does not always know the product boundary, the non-goals, the previous decisions, or the intended lifecycle of a feature. Over time, this creates a familiar mess:

“Why did the agent implement this extra thing?”
“Why did it change unrelated code?”
“Where is the actual product behavior documented?”
“Which spec is current and which one was just a temporary plan?”
“Why is the README saying one thing and the code doing another?”

This is where Spec-Driven Development, or SDD, becomes useful.

In this post, I want to explain SDD from a practical point of view: not as theory, not as a strict enterprise process, and not as a replacement for engineering judgment. I see it as a lightweight workflow for building software with AI coding agents.

I will use the workflow I used in my own Java CLI project, AgentTokenInsight, as the example.


I do not see SDD as a replacement for coding, testing, or engineering judgment.

I also do not see it as a heavy enterprise process that every tiny change must follow.

For me, lightweight SDD is useful when an AI coding agent is powerful enough to change a lot of code quickly. The goal is not to slow the agent down. The goal is to give it a clear boundary.

Use SDD for product behavior, APIs, CLI behavior, libraries, compatibility-sensitive changes, and multi-step features.

Do not force it for typos, tiny refactors, throwaway scripts, or experiments.

The point is not documentation. The point is controlled delegation.


What is Spec-Driven Development?

Spec-Driven Development means we do not jump directly from idea to implementation.

Instead, every meaningful change goes through a small lifecycle:

propose → review → apply → test → sync → archive

In plain English:

  1. First, define what should change.
  2. Clarify why it should change.
  3. Write the expected behavior.
  4. List tasks.
  5. Review the scope before implementation.
  6. Implement only that approved scope.
  7. Run tests.
  8. Update the current product spec if behavior changed.
  9. Archive the completed change.

The propose step can create several files, such as:

proposal.md
design.md
tasks.md
spec.md

This is not the same as writing huge requirements documents. In fact, it should be the opposite.

A good SDD workflow should be small, practical, and close to the code.


Why SDD Matters More with AI Coding Agents

Traditional development already benefits from clear specs. But with AI agents, the value becomes much higher.

Why?

Because AI agents are powerful, but they do not always know the real boundary of a task.

Imagine you have a large Java backend project and you ask the agent:

Fix the login timeout bug.

To solve that bug, the agent may only need to inspect a few files:

src/main/java/com/example/auth/LoginService.java
src/main/java/com/example/auth/SessionManager.java
src/test/java/com/example/auth/LoginServiceTest.java

But if the task is not scoped, the agent may start exploring much more:

- all authentication classes
- security configuration
- application.yml
- web.xml
- all session-related tests
- unrelated user-management code
- generated files
- build output
- old archived code

At that point, the agent is not necessarily “wrong”. It is trying to understand the system. But the context has become too large, the token cost has increased, and the change is now harder to review.

The original task was:

Fix the login timeout bug.

But the actual work may turn into:

Analyze half of the authentication module, read several config files, update tests, and maybe touch unrelated code.

This is the kind of drift SDD helps prevent.

Before implementation, the spec can define the boundary clearly:

Scope:
- investigate login timeout behavior
- start with LoginService and SessionManager
- update related tests only if needed

Non-goals:
- refactoring the whole authentication module
- changing security configuration
- changing production config files
- touching unrelated user-management code

Now the agent has a much clearer task. It can still ask to expand the scope, but it should not silently turn a focused bug fix into a broad project investigation.

This gives the AI agent a much better box to work inside.


The Workflow I Use

I use a lightweight internal spec workflow with this structure:

spec/
  WORKFLOW.md
  project.md
  current/
    agenttokeninsight.md
  changes/
    .gitkeep
  archive/

And project-local Codex skills:

.codex/skills/
  spec-propose/
    SKILL.md
  spec-apply/
    SKILL.md
  spec-sync/
    SKILL.md
  spec-archive/
    SKILL.md
  spec-explore/
    SKILL.md

The commands are intentionally simple:

$spec-propose add-feature-name
$spec-apply add-feature-name
$spec-sync add-feature-name
$spec-archive add-feature-name
$spec-explore

These are not universal built-in commands. In my project, they are project-local Codex skills that enforce the workflow.

The important point is not the exact command name. The important point is the lifecycle.


Influences

This workflow is my own lightweight version for this project, but it is influenced by the broader Spec-Driven Development ecosystem.

Tools and projects such as OpenSpec and GitHub Spec Kit helped popularize the idea of using structured specs to guide AI coding agents.

I did not want to copy a full framework into this project. Instead, I kept the parts that matched my needs: small proposals, explicit non-goals, living specs, and archived change history.


The Core Folder Roles

spec/project.md

This is the project guidance file.

It contains things like:

- project purpose
- tech stack
- constraints
- naming decisions
- architectural boundaries
- things not to add unless explicitly requested

For AgentTokenInsight, this includes guidance like:

- Java 25
- Gradle Kotlin DSL
- Picocli
- Jackson YAML and JSON
- JUnit 5
- AssertJ
- deterministic approximate token estimates
- no Spring Boot, no web dashboard, no database unless later specified

This file helps the agent understand the project before touching code.

spec/current/agenttokeninsight.md

This is the living spec.

The living spec is not the dream, the roadmap, or the original proposal.

It is the current observable behavior of the product.

If the code changes user-visible behavior, the living spec should change too. If the code only refactors internals, the living spec probably should not change.

For example:

AgentTokenInsight must support loading configuration from agenttoken.yml.
AgentTokenInsight must support scanning a repository from a root directory.
AgentTokenInsight must support generating Markdown reports.
AgentTokenInsight must support JSON output from agenttoken scan --format json.

This file is the product truth.

spec/changes/<change-name>/

Every active change gets its own folder:

spec/changes/add-scan-insights/
  proposal.md
  design.md
  tasks.md
  spec.md

This is where new work is planned before implementation.

spec/archive/

When a change is completed, it moves to archive.

Archive is history. Do not rewrite it casually.


What Goes into a Change?

A typical change contains four files.

proposal.md

The proposal answers:

What are we changing?
Why are we changing it?
What is in scope?
What is out of scope?

Example:

# add-cli-json-format-option

## Summary
Add a --format option to agenttoken scan so the CLI can render either Markdown or JSON output.

## Why
Human users need Markdown by default, while automation needs JSON.

## Scope
- agenttoken scan continues to print Markdown by default
- agenttoken scan --format markdown prints Markdown
- agenttoken scan --format json prints JSON
- invalid format values fail clearly

## Non-goals
- changing repository scanning behavior
- changing budget validation behavior
- writing reports to files
- adding GitHub Actions

The non-goals are extremely important. They reduce agent drift.

design.md

The design explains the approach.

It does not need to be long.

Example:

# Design

The scan command should treat report format as an output concern only.

The command should map:
- markdown -> MarkdownReportGenerator
- json -> JsonReportGenerator

The scanner and validator must not change.

tasks.md

This is the implementation checklist.

Example:

# Tasks

- [ ] Add --format option to scan.
- [ ] Keep Markdown as default.
- [ ] Route JSON output through JsonReportGenerator.
- [ ] Fail clearly on unsupported format values.
- [ ] Add tests for default Markdown.
- [ ] Add tests for JSON output.
- [ ] Add tests for invalid format.

spec.md

This describes observable behavior.

Example:

# AgentTokenInsight Scan Format Selection

## Requirement 1: AgentTokenInsight must support selecting scan report format from the CLI

The CLI must provide a --format option for agenttoken scan.
When the option is omitted, the command must print Markdown by default.
When --format markdown is provided, the command must print Markdown.
When --format json is provided, the command must print JSON.
The command must fail clearly when an unsupported format value is provided.

### Scenario: Markdown is the default
Given a user runs agenttoken scan without specifying --format
When the command completes successfully
Then the CLI prints Markdown output

### Scenario: JSON is requested explicitly
Given a user runs agenttoken scan --format json
When the command completes successfully
Then the CLI prints JSON output

This gives the agent a testable contract.


Apply: Implementation Comes After Review

After the change is reviewed, implementation starts.

The apply step should read:

spec/project.md
spec/changes/<change-name>/proposal.md
spec/changes/<change-name>/design.md
spec/changes/<change-name>/tasks.md
spec/changes/<change-name>/spec.md

Then it should implement only that scope.

The rule is:

Do not implement non-goals.
Do not sync living specs automatically.
Do not archive automatically.

That separation matters.

Implementation is one step.
Spec sync is another.
Archiving is another.

This keeps the workflow controlled.


Sync: Updating the Living Spec

After code is implemented and tested, the living spec must be updated if product behavior changed.

This is the step many teams skip.

They write a design once, implement the code, and then the design becomes stale.

That is not a living spec. That is documentation debt.

For example, after adding JSON output, the current spec should now include:

AgentTokenInsight must support agenttoken scan --format json.

But it should not include implementation notes that are no longer relevant.

The living spec should describe the product, not the temporary development plan.


Archive: Keeping History Without Polluting Current Truth

Once a change is implemented and the living spec is updated, the change folder moves to archive:

spec/changes/add-cli-json-format-option/

becomes:

spec/archive/add-cli-json-format-option/

The archive is useful because it answers:

Why did we add this?
What was the original scope?
What were the non-goals?
What tasks were done?

But archive is not the current product truth.

The living spec is.


When Should You Update the Living Spec?

You should update the living spec when behavior changes.

Good reasons to update:

- new CLI command
- new config option
- changed output format
- changed validation behavior
- changed error handling
- changed public API
- changed generated report structure

You probably do not need to update the living spec for:

- internal refactor with no behavior change
- test-only cleanup
- formatting changes
- dependency patch with no observable behavior change
- README typo fix

A simple rule:

If a user, caller, or integrator can observe the change, update the living spec.


SDD and Token Usage

Spec-Driven Development can reduce token waste when working with AI agents.

Not because specs are free. They are not. Specs also consume tokens.

But SDD reduces the expensive kind of waste:

- repeated explanation
- agent misunderstanding
- unrelated code changes
- rework
- large context dumps
- rediscovering project decisions
- debugging wrong assumptions

Without SDD, you may keep writing prompts like:

No, don't change the CLI.
No, don't add JSON yet.
No, don't touch scanner behavior.
No, the config file is agenttoken.yml now.
No, Java packages should stay under com.agenttoken.

With SDD, these decisions live in project guidance and current specs.

That makes prompts shorter.

Instead of explaining the whole project again, you can say:

$spec-apply add-scan-insights
Implement only this approved change.

The agent has a smaller and clearer target.

SDD Uses Tokens Upfront to Save Tokens Later

This is the tradeoff.

SDD adds upfront writing:

proposal.md
design.md
tasks.md
spec.md

But it can save tokens later by reducing:

misimplementation
backtracking
scope creep
review noise
repeated context

For small changes, the overhead may not be worth it.

For medium or complex changes, it often is.


Tradeoffs of Spec-Driven Development

SDD is not magic. It has costs.

It also does not make bad intent safe. If the spec is vague, wrong, or too broad, the agent may still produce the wrong thing - just with more confidence.

Benefits

- clearer feature boundaries
- better AI agent control
- fewer unrelated changes
- better review process
- current product behavior is documented
- easier onboarding
- easier release preparation
- more stable architecture decisions

Costs

- more files
- more process
- slower start for tiny changes
- living specs require discipline
- bad specs can mislead agents
- too much detail can waste tokens

The goal is not to write more documentation.

The goal is to write just enough structure to make implementation safer and faster.


When SDD Makes Sense

SDD is a good fit when:

- you are using an AI coding agent heavily
- the project has multiple features
- scope control matters
- behavior should remain stable
- you want repeatable implementation flow
- multiple sessions or contributors will touch the project
- release quality matters

It is especially useful for:

- CLI tools
- libraries
- APIs
- developer tools
- automation tools
- products with evolving behavior

AgentTokenInsight is a good example because it has:

- CLI commands
- config files
- validators
- reports
- packaging
- user-visible behavior

That kind of project benefits from a living spec.


When SDD Is Too Much

SDD may not be worth it for:

- a 30-line script
- a quick local experiment
- throwaway prototype
- one-time data conversion
- purely visual exploration

For those, a simple checklist or short prompt is enough.

Do not turn SDD into ceremony.

The point is control, not bureaucracy.


Example: AgentTokenInsight Feature Flow

Here is a real-style flow.

Step 1: Propose

$spec-propose add-scan-insights

Creates:

spec/changes/add-scan-insights/
  proposal.md
  design.md
  tasks.md
  spec.md

Proposal:

## Summary
Add actionable insights to scan reports.

## Why
Users need to understand why a scope is too large and what to do next.

## Scope
- Add Insights section to Markdown reports.
- Add insights array to JSON reports.
- Generate deterministic insights from scan and validation results.

## Non-goals
- AI-generated recommendations
- model-specific tokenization
- changing scanner behavior
- changing CLI commands

Step 2: Review

Before coding, review the spec.

Ask:

Is the scope small?
Are non-goals clear?
Is the behavior testable?
Could this accidentally change existing behavior?

Step 3: Apply

$spec-apply add-scan-insights

The implementation should only do what the change says.

Step 4: Test

./gradlew test

Step 5: Sync

$spec-sync add-scan-insights

Update:

spec/current/agenttokeninsight.md

Step 6: Archive

$spec-archive add-scan-insights

Move the completed change to:

spec/archive/add-scan-insights/

This gives us both current truth and historical context.


How This Helps AI Agent Work

The most important benefit is not documentation.

The most important benefit is controlled delegation.

When working with an AI coding agent, you are delegating implementation. SDD gives the agent a contract.

Without SDD:

“Add scan insights.”

With SDD:

“Implement the approved add-scan-insights change.
Read proposal, design, tasks, and spec.
Do not implement non-goals.
Do not change scanner behavior.
Add tests.”

That is a much better instruction.

It reduces ambiguity.

It also gives you better review points:

Review proposal before implementation.
Review implementation before sync.
Review living spec before archive.

The Future of SDD

I think SDD will become more important as AI coding agents become more capable.

Why?

Because the more powerful the agent, the more important the boundary becomes.

A weak assistant needs help writing code.
A strong assistant needs clear constraints.

Future development may look less like:

developer writes every line of code

and more like:

developer defines intent, constraints, tests, and product boundaries
agent implements
developer reviews and steers

In that world, specs are not bureaucracy.

Specs are the interface between human intent and agent execution.

A good spec tells the agent:

what to do
why it matters
what not to do
how success is observed
where current truth lives

That is exactly the kind of structure AI development needs.


Practical Rules for Lightweight SDD

1. One change at a time

Do not combine unrelated changes.

Good:

add-json-output

Bad:

add-json-output-and-github-actions-and-refactor-scanner

2. Always write non-goals

Non-goals are often more important than scope.

They stop agent drift.

3. Keep design short

A design does not need to be a novel.

A few clear paragraphs are enough.

4. Requirements should be observable

Avoid vague specs like:

The system should be better.

Prefer:

When agenttoken scan --format json runs, the output must be valid JSON and include scannedFileCount.

5. Do not sync before implementation

The living spec should describe current behavior, not planned behavior.

6. Archive is history

Do not rewrite old archived changes just because the product was renamed later.

If the current behavior changed, update current spec.
If history says something old, let it remain history.

7. Use SDD where it pays off

Use it for product behavior.

Do not force it for every typo.


Conclusion

Spec-Driven Development is not about writing documents for the sake of documents.

It is about creating a lightweight control system for software changes, especially when AI coding agents are involved.

For me, the useful pattern is:

propose → review → apply → test → sync → archive

The propose step may create proposal.md, design.md, tasks.md, and spec.md. The important part is that implementation starts only after the scope is clear enough to review.

This gives the AI agent enough structure to work effectively without giving it unlimited freedom to reshape the project.

In AgentTokenInsight, this workflow helped keep changes small, reviewable, and aligned with the product goal.

The biggest lesson is simple:

The stronger the coding agent becomes, the more valuable clear specs become.

Not because the agent is weak.

Because the agent is powerful.

And powerful tools need boundaries.

Sunday

animated square stroke - css

<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">

  <path fill="white" stroke="black" stroke-width="4"  class="path" d="M 10 10 H 90 V 90 H 10 L 10 10"/>

  <!-- Points -->
  <circle cx="10" cy="10" r="2" fill="red"/>
  <circle cx="90" cy="90" r="2" fill="red"/>
  <circle cx="90" cy="10" r="2" fill="red"/>
  <circle cx="10" cy="90" r="2" fill="red"/>
</svg>

.path {
  stroke-dasharray: 320;
  stroke-dashoffset: 320;
  animation: dash 8s linear  infinite;
}

@keyframes dash {
  from {
    stroke-dashoffset: 320;
  }

  to {
    stroke-dashoffset: 0;
  }
}

Screenshot:



 



An example of converting object to an array in javascript


const ingredients = {
 salad: 2,
 tomato: 1,
 cheese: 3,
 meat: 2
}

const transformedIngredients = Object.keys(ingredients)
  .map(iKey => {
     return [...Array(ingredients[iKey])].map((_, i) => {
       return iKey ;
   });
}); 

console.log(transformedIngredients.toString());
the output is: salad,salad,tomato,cheese,cheese,cheese,meat,meat

**Object.keys(ingredients) returns key list:   salad,tomato,cheese,meat
**Array(ingredients[iKey])   returns the value of the given key like salad. for instance,the output for salad: Array(2). so the second map loops 2 time and returns salad twice.

enable css loader >> unknown property 'localIdentName' error

versions >>  "css-loader":"3.4.2"

firstly looking: (in the project created by create-react-app which has been ejected)
{
  test: cssRegex,
  exclude: cssModuleRegex,
  use: getStyleLoaders({
 importLoaders: 1,
 sourceMap: isEnvProduction && shouldUseSourceMap,
  }),
  sideEffects: true,
},
I tried: (this one is the older config)
{
  test: cssRegex,
  exclude: cssModuleRegex,
  use: getStyleLoaders({
 importLoaders: 1,
 modules: true,
 localIdentName: "[name]__[local]___[hash:base64:5]",
 sourceMap: isEnvProduction && shouldUseSourceMap,
  }),
  sideEffects: true,
},
i got following error:
./src/index.css (./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-3-1!./node_modules/postcss-loader/src??postcss!./src/index.css)
ValidationError: Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema.
 - options has an unknown property 'localIdentName'. These properties are valid:
   object { url?, import?, modules?, sourceMap?, importLoaders?, localsConvention?, onlyLocals?, esModule? }

FIX:
 {
  test: cssRegex,
  exclude: cssModuleRegex,
  use: getStyleLoaders({
 importLoaders: 1,
 modules: {
   localIdentName: "[name]__[local]___[hash:base64:5]",
 }, 
 sourceMap: isEnvProduction && shouldUseSourceMap,
  }),
  sideEffects: true,
},

Saturday

How to copy given text to the clipboard in react with typescript


import React from 'react';
import { LightTooltip } from '../tooltip/lightTooltip';

interface IOwnProps {
  messageToBeCopied: string | null;
}

export default class CopyToClipboard extends React.Component<IOwnProps> {

  render() {
    const { messageToBeCopied, children } = this.props;
    let isCopySuccess = false;

    if (messageToBeCopied) {
      try {
        const textField = document.createElement('textarea');
        textField.innerText = messageToBeCopied;
        document.body.appendChild(textField);
        textField.select();

        isCopySuccess = document.execCommand('copy');
        textField.remove();

      } catch (e) {
        isCopySuccess = false;
      }

      return (
        <LightTooltip
          leaveDelay={1}
          leaveTouchDelay={1}
          title={isCopySuccess === false ? 'Failed to copy.' : 'Copied.'}
        >
          {children as React.ReactElement}
        </LightTooltip>
      );
    }

    return <>{children}</>;
  }
}

import { withStyles, Theme } from '@material-ui/core/styles';
import Tooltip from '@material-ui/core/Tooltip';

export  const LightTooltip = withStyles((theme: Theme) => ({
  tooltip: {
    backgroundColor: theme.palette.common.white,
    color: 'rgba(0, 0, 0, 0.87)',
    boxShadow: theme.shadows[1],
    fontSize: 12,
    fontFamily: 'Rubik-Regular',
  },
}))(Tooltip);

import React from 'react';
import CopyToClipboard from '../copyToClipboard/copyToClipboard';

interface IState {
  clipboardMessage: string | null;
}

class Example extends React.Component<null, IState> {
  constructor(props) {
    super(props);
    this.state = {
      clipboardMessage: null,
    };
  }

  setClipboardMessage() {
    const message = 'Message for copy to clipboard';

    this.setState({
      clipboardMessage: message,
    });
  }

  render() {
    return (
      <CopyToClipboard messageToBeCopied={this.state.clipboardMessage}>
        <a onClick={() => this.setClipboardMessage()}>Copy</a>
      </CopyToClipboard>
    );
  }
}

export default Example;
Example screenshot after clicking the text:

How to add fonts into react project

Define your font as follows in your app.scss/app.css :
(You can use your fonts as named in font-family.)
@font-face {
  font-family: 'Rubik-Regular';
  src: local('Rubik'), url(../static/font/Rubik/Rubik-Regular.ttf) format('truetype');
}

@font-face {
  font-family: 'Rubik-Medium';
  src: local('Rubik'), url(../static/font/Rubik/Rubik-Medium.ttf) format('truetype');
}

Add font files into src/static/font/..



















Convert currency code to symbol in react with typescript


import { currencyMap } from './currencyMap';

export default function  getSymbolFromCurrencyCode(currencyCode : string) {
  const code = currencyCode && currencyCode.toUpperCase();
  if (!currencyMap.hasOwnProperty(code)) {
    return currencyCode;
  }
  return currencyMap[code];
}

export const currencyMap = {
  'AED': 'د.إ',
  'AFN': '؋',
  'ALL': 'L',
  'AMD': '֏',
  'ANG': 'ƒ',
  'AOA': 'Kz',
  'ARS': '$',
  'AUD': '$',
  'AWG': 'ƒ',
  'AZN': '₼',
  'BAM': 'KM',
  'BBD': '$',
  'BDT': '৳',
  'BGN': 'лв',
  'BHD': '.د.ب',
  'BIF': 'FBu',
  'BMD': '$',
  'BND': '$',
  'BOB': '$b',
  'BRL': 'R$',
  'BSD': '$',
  'BTC': '฿',
  'BTN': 'Nu.',
  'BWP': 'P',
  'BYR': 'Br',
  'BYN': 'Br',
  'BZD': 'BZ$',
  'CAD': '$',
  'CDF': 'FC',
  'CHF': 'CHF',
  'CLP': '$',
  'CNY': '¥',
  'COP': '$',
  'CRC': '₡',
  'CUC': '$',
  'CUP': '₱',
  'CVE': '$',
  'CZK': 'Kč',
  'DJF': 'Fdj',
  'DKK': 'kr',
  'DOP': 'RD$',
  'DZD': 'دج',
  'EEK': 'kr',
  'EGP': '£',
  'ERN': 'Nfk',
  'ETB': 'Br',
  'ETH': 'Ξ',
  'EUR': '€',
  'FJD': '$',
  'FKP': '£',
  'GBP': '£',
  'GEL': '₾',
  'GGP': '£',
  'GHC': '₵',
  'GHS': 'GH₵',
  'GIP': '£',
  'GMD': 'D',
  'GNF': 'FG',
  'GTQ': 'Q',
  'GYD': '$',
  'HKD': '$',
  'HNL': 'L',
  'HRK': 'kn',
  'HTG': 'G',
  'HUF': 'Ft',
  'IDR': 'Rp',
  'ILS': '₪',
  'IMP': '£',
  'INR': '₹',
  'IQD': 'ع.د',
  'IRR': '﷼',
  'ISK': 'kr',
  'JEP': '£',
  'JMD': 'J$',
  'JOD': 'JD',
  'JPY': '¥',
  'KES': 'KSh',
  'KGS': 'лв',
  'KHR': '៛',
  'KMF': 'CF',
  'KPW': '₩',
  'KRW': '₩',
  'KWD': 'KD',
  'KYD': '$',
  'KZT': 'лв',
  'LAK': '₭',
  'LBP': '£',
  'LKR': '₨',
  'LRD': '$',
  'LSL': 'M',
  'LTC': 'Ł',
  'LTL': 'Lt',
  'LVL': 'Ls',
  'LYD': 'LD',
  'MAD': 'MAD',
  'MDL': 'lei',
  'MGA': 'Ar',
  'MKD': 'ден',
  'MMK': 'K',
  'MNT': '₮',
  'MOP': 'MOP$',
  'MRO': 'UM',
  'MRU': 'UM',
  'MUR': '₨',
  'MVR': 'Rf',
  'MWK': 'MK',
  'MXN': '$',
  'MYR': 'RM',
  'MZN': 'MT',
  'NAD': '$',
  'NGN': '₦',
  'NIO': 'C$',
  'NOK': 'kr',
  'NPR': '₨',
  'NZD': '$',
  'OMR': '﷼',
  'PAB': 'B/.',
  'PEN': 'S/.',
  'PGK': 'K',
  'PHP': '₱',
  'PKR': '₨',
  'PLN': 'zł',
  'PYG': 'Gs',
  'QAR': '﷼',
  'RMB': '¥',
  'RON': 'lei',
  'RSD': 'Дин.',
  'RUB': '₽',
  'RWF': 'R₣',
  'SAR': '﷼',
  'SBD': '$',
  'SCR': '₨',
  'SDG': 'ج.س.',
  'SEK': 'kr',
  'SGD': '$',
  'SHP': '£',
  'SLL': 'Le',
  'SOS': 'S',
  'SRD': '$',
  'SSP': '£',
  'STD': 'Db',
  'STN': 'Db',
  'SVC': '$',
  'SYP': '£',
  'SZL': 'E',
  'THB': '฿',
  'TJS': 'SM',
  'TMT': 'T',
  'TND': 'د.ت',
  'TOP': 'T$',
  'TRL': '₤',
  'TRY': '₺',
  'TL': '₺',
  'TTD': 'TT$',
  'TVD': '$',
  'TWD': 'NT$',
  'TZS': 'TSh',
  'UAH': '₴',
  'UGX': 'USh',
  'USD': '$',
  'UYU': '$U',
  'UZS': 'лв',
  'VEF': 'Bs',
  'VND': '₫',
  'VUV': 'VT',
  'WST': 'WS$',
  'XAF': 'FCFA',
  'XBT': 'Ƀ',
  'XCD': '$',
  'XOF': 'CFA',
  'XPF': '₣',
  'YER': '﷼',
  'ZAR': 'R',
  'ZWD': 'Z$',
}
Example:
import getSymbolFromCurrencyCode from '../commons/currencySymbol/currencySymbolMap';

...
getSymbolFromCurrencyCode('TRY');
...

Typescript index signature example


import Example1 from '../../components/……....';
import Example2 from '../../components/…....';


interface ExampleInfos {
  name: any;
  param1: string;
  param2?: boolean;
}


interface ExampleLayout {
  [key:string]: ExampleInfos;
}


export const exampleMap: ExampleLayout = {
  example1: {
    name: Example1,
    param1: 'medium',
  },
  example2: {
    name: Example2,
    param1: 'medium',
    param2: false,
  },
}


import { exampleMap } from './exampleMap';

...
 const myMap= exampleMap['example1'];
 const myComponent = myMap && myMap.name;
...