adding skills / agents / other to config
This commit is contained in:
22
ai/RULES.md
Normal file
22
ai/RULES.md
Normal file
@@ -0,0 +1,22 @@
|
||||
## HARD MANDATE: PLAN BEFORE ACTION
|
||||
- **No Unapproved State Changes:** You MUST NOT execute any tool that modifies the filesystem, runs shell commands (excluding read-only discovery like `ls` or `grep`), or changes system state without first presenting a detailed plan and receiving an explicit "Directive" (e.g., "proceed") from the user. This rule is absolute. REQUIRED!
|
||||
|
||||
## Gemini Added Memories
|
||||
- When working on the Hugo wiki, docs, or Caddy routing, immediately run the docs_architecture skill to understand the decoupled architecture, deployment logic, and known Docker/Caddy networking quirks.
|
||||
- When writing Hugo/Blowfish Markdown front matter, always include 'author', 'date' (ISO-8601), 'lastmod' (YYYY-MM-DD), and 'tags' (list) at the bottom of the metadata block.
|
||||
- Never perform manual builds or deployments of the Hugo sites to bypass the CI/CD pipeline. Always rely on the Gitea Actions workflows for deployment.
|
||||
- Avoid making direct edits to Nginx Proxy Manager .conf files because it causes a desync with the Web UI database. Always prefer asking the user to make changes via the NPM Web UI instead. If a direct edit is absolutely necessary, always remind the user that the UI will be out of sync.
|
||||
- When generating dates for Hugo/Blowfish front matter (or any timestamps), never use UTC (Z). Always use EST (America/New_York) timezone offsets (e.g., -05:00 for EST or -04:00 for EDT).
|
||||
- For all Markdown files, always ensure there is exactly one empty newline immediately following any heading (e.g., # Heading, ## Subheading).
|
||||
- Always present a detailed summary of planned changes (identifying specific files and the nature of the edits) before executing any modifications. You MUST explicitly ask the user for permission to proceed and wait for a "Directive" before acting.
|
||||
- When creating callouts or admonitions in Hugo Markdown files, always use the `> [!TYPE]` blockquote syntax (supported by the `hugo-admonitions` render hook) instead of theme-specific shortcodes.
|
||||
|
||||
## REQUIRED! Workflow
|
||||
- **Evaluate Prompt:** For every user request, first decide if specific skills/agents (e.g., codebase_investigator) are required. REQUIRED!
|
||||
- **Present Plan:** Always create a clear plan and present it to the user. Do not act until a "Directive" (e.g., "proceed") is given. REQUIRED!
|
||||
- **Logging:** For every resolved prompt, append a log entry to the project directory. REQUIRED!
|
||||
- Format: Use a Markdown table.
|
||||
- Columns: `| Date (EST) | Prompt | Resolution Steps (Detailed Files/Paths/Tools) |`.
|
||||
- Rule: Never remove or overwrite entries; only append.
|
||||
- Timezone: Always use EST/EDT offsets.
|
||||
- Confirm the project directory by asking the user.
|
||||
BIN
ai/skills/.DS_Store
vendored
Normal file
BIN
ai/skills/.DS_Store
vendored
Normal file
Binary file not shown.
22
ai/skills/architecture_reviewer/SKILL.md
Normal file
22
ai/skills/architecture_reviewer/SKILL.md
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
name: architecture-reviewer
|
||||
description: Expert skill for reviewing system architecture, design patterns, and scalability using public industry standards.
|
||||
---
|
||||
|
||||
# Architecture Reviewer Skill
|
||||
|
||||
This skill provides high-level design oversight, ensuring systems are resilient, scalable, and follow modern architectural patterns (e.g., Microservices, Event-Driven Architecture, 12-factor apps).
|
||||
|
||||
## Principles
|
||||
|
||||
1. **Public Standard Alignment**: Use world-class architectural principles (e.g., AWS Well-Architected Framework, Google Cloud Architecture Framework - public-facing).
|
||||
2. **Scalability & Resilience**: Evaluate designs for potential bottlenecks, single points of failure, and horizontal scalability.
|
||||
3. **Interface Design**: Favor gRPC/Protocol Buffers (public) or RESTful APIs (standardized) for component communication.
|
||||
4. **Security-First**: Ensure Zero Trust principles and data encryption are considered early in the planning.
|
||||
5. **Simplicity over Complexity**: Strongly favor simple, well-understood patterns over complex, custom solutions.
|
||||
|
||||
## Architecture Review Checklist
|
||||
- Is the system decoupled?
|
||||
- Are the data storage solutions appropriate for the access patterns?
|
||||
- How is observability (monitoring/logging) handled using public tools?
|
||||
- Does the design avoid vendor lock-in where possible?
|
||||
23
ai/skills/code_quality/SKILL.md
Normal file
23
ai/skills/code_quality/SKILL.md
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
name: code_quality_expert
|
||||
description: Foundational skill for enforcing general code quality standards, SOLID principles, and software engineering best practices.
|
||||
---
|
||||
|
||||
# Code Quality Expert Skill
|
||||
|
||||
This skill ensures that all code produced or reviewed by the agent adheres to high-quality software engineering standards, regardless of the target language.
|
||||
|
||||
## Principles
|
||||
|
||||
1. **SOLID Principles**: Ensure single responsibility, open-closed, Liskov substitution, interface segregation, and dependency inversion.
|
||||
2. **DRY (Don't Repeat Yourself)**: Avoid redundant logic by abstracting it into reusable components.
|
||||
3. **KISS (Keep It Simple, Stupid)**: Prioritize simple, readable code over clever, complex solutions.
|
||||
4. **Meaningful Naming**: Use descriptive and consistent names for variables, functions, and classes.
|
||||
5. **Testability**: Design code that is easy to test using unit, integration, and end-to-end tests.
|
||||
6. **Style Guide Adherence**: Enforce language-specific style guides (e.g., Google Python Style Guide, PEP 8) in the public domain.
|
||||
|
||||
## Code Quality Checklist
|
||||
- Is the code readable and well-documented?
|
||||
- Are there any potential performance or security risks?
|
||||
- Is the error handling robust and appropriate?
|
||||
- Are there any architectural violations?
|
||||
27
ai/skills/core/SKILL.md
Normal file
27
ai/skills/core/SKILL.md
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
name: framework_core
|
||||
description: General-purpose skill for maintaining the Gemini Workflow Framework and following its core rules.
|
||||
---
|
||||
# Framework Core Skill
|
||||
|
||||
This skill ensures that all Gemini interactions adhere to the rules defined in `GEMINI.md`.
|
||||
|
||||
## Available Experts
|
||||
- **Lisp**: `lisp_expert`
|
||||
- **Go**: `go_expert`
|
||||
- **HTML/CSS**: `html_css_expert`
|
||||
- **JavaScript**: `javascript_expert`
|
||||
- **Java**: `java_expert`
|
||||
- **JSON**: `json_expert`
|
||||
- **Markdown**: `markdown_expert`
|
||||
- **Shell**: `shell_expert`
|
||||
- **Code Quality**: `code_quality_expert`
|
||||
- **Architecture**: `architecture_reviewer`
|
||||
|
||||
## Guidelines
|
||||
|
||||
1. **Rule Enforcement**: Before every major action, verify it against the rules in `GEMINI.md`.
|
||||
2. **Mandatory Expert Loading**: For any task involving a specific language or domain, you MUST load and follow the corresponding expert skill.
|
||||
3. **External Auditing**: Always search for public-facing alternatives to internal Google tools.
|
||||
4. **Planning Discipline**: Maintain the "Planning Phase" until explicit user approval for implementation is received.
|
||||
5. **Interactive Clarification**: Use the `ask_question` pattern if a user request deviates from the established workflow framework.
|
||||
61
ai/skills/docs_architecture/SKILL.md
Normal file
61
ai/skills/docs_architecture/SKILL.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# Docs Architecture Skill
|
||||
|
||||
This skill documents the exact technical architecture, routing, and deployment workflow for WompMacho's decoupled Hugo/Gitea/Caddy Wiki infrastructure.
|
||||
|
||||
## 🏗️ 1. Core Architecture (Decoupled Repositories)
|
||||
|
||||
The system is split into three independent Git repositories hosted on `git.wompmacho.com`:
|
||||
|
||||
1. **Framework (`/srv/dev/hugo/wiki`)**: Repository `hugo-framework`
|
||||
* **Purpose**: The central Hugo engine. Contains the Blowfish theme as a submodule (`themes/blowfish`) and the master `config/_default/params.toml`.
|
||||
* **Rule**: NEVER place content (`.md` files) here. NEVER place environment-specific overrides (like hardcoded `editURLs` or top-level menus) in the global `params.toml`.
|
||||
|
||||
2. **Public Wiki (`/srv/docs/public`)**: Repository `docs-public`
|
||||
* **Purpose**: Public-facing markdown notes, assets (`/static`), and its own top-bar menu configuration (`config/_default/menus.en.toml`).
|
||||
* **Deployment Target**: `/srv/caddy/sites/wiki`
|
||||
* **Live URL**: `https://wiki.wompmacho.com` (proxied by NPM).
|
||||
|
||||
3. **Private Wiki (`/srv/docs/private`)**: Repository `docs-private`
|
||||
* **Purpose**: Personal, private markdown notes, assets (`/static`), and its own top-bar menu configuration (`config/_default/menus.en.toml`).
|
||||
* **Deployment Target**: `/srv/caddy/sites/private-wiki`
|
||||
* **Live URL**: `http://10.0.0.190:9897` (or `http://private` via NPM).
|
||||
|
||||
## 💻 2. Local Development ("Live Link")
|
||||
|
||||
When working on content, the user uses **Code-Server**. To see real-time updates without deploying, the `hugo-framework` repository uses symbolic links.
|
||||
|
||||
* `content -> /srv/docs/public`
|
||||
* `static -> /srv/docs/public/static`
|
||||
|
||||
**Command to start local preview**: `cd /srv/dev/hugo/wiki && hugo server --bind 0.0.0.0 --appendPort=false --baseURL="/"`
|
||||
|
||||
## 🚀 3. CI/CD Pipeline (Gitea Actions)
|
||||
|
||||
Both `docs-public` and `docs-private` have a `.gitea/workflows/deploy.yaml` action.
|
||||
|
||||
### The Build Process
|
||||
1. **Checkout Content**: The runner checks out the markdown content.
|
||||
2. **Clone Framework**: The runner natively clones the `hugo-framework` (including submodules) using `git clone --recurse-submodules https://git.wompmacho.com/wompmacho/hugo-framework.git`.
|
||||
3. **Inject Content**: Markdown and static files are copied into the framework's workspace.
|
||||
4. **Inject Dynamic Menus**: The `config/_default/menus.en.toml` is injected, automatically overriding the framework's top navigation bar for that specific site.
|
||||
5. **Inject Edit Links (CRITICAL RULE)**: The "Edit this page" link on the bottom of posts MUST NOT be configured via a `params.toml` override, as Hugo replaces the entire file instead of merging it, destroying the Blowfish styling.
|
||||
* **Fix**: It is injected dynamically via an Environment Variable right before the build command:
|
||||
* `HUGO_PARAMS_ARTICLE_EDITURL="https://git.../src/branch/main" hugo --minify ...`
|
||||
6. **Deploy**: The output `/public` folder is copied directly to the mounted `/deploy` volume.
|
||||
|
||||
## 🌐 4. Web Server Routing (Nginx)
|
||||
|
||||
The system relies on two extremely lightweight `nginx:alpine` containers defined in `gitea/docker-compose.yaml` to serve static files. They act as "dumb" file servers behind Nginx Proxy Manager (NPM), bypassing the complex Host header validation and 0-byte security issues inherent to Caddy.
|
||||
|
||||
1. **Public (`public_wiki` - Port 9896)**:
|
||||
* Mounts `/srv/caddy/sites/wiki` as read-only.
|
||||
* NPM routes `wiki.wompmacho.com` to Docker Host IP on port `9896`.
|
||||
2. **Private (`private_wiki` - Port 9897)**:
|
||||
* Mounts `/srv/caddy/sites/private-wiki` as read-only.
|
||||
* NPM routes `http://private` to Docker Host IP on port `9897`.
|
||||
|
||||
## 🛠️ 5. Known Quirks and Formatting Rules
|
||||
|
||||
* **Submodules**: Always use `git submodule add -b main <url>` and ensure the commit pointer is tracked. Do not copy theme files physically.
|
||||
* **Blowfish Homepage**: If the homepage is blank, it means there are no recent posts. By default, Blowfish's `home` layout only lists files with `type: "article"` or `type: "posts"`. For generic folders, set `type: "page"` and `layout: "list"` in `_index.md`.
|
||||
* **Frontmatter**: Blowfish expects standard Hugo frontmatter (`date:` as a string, `authors: ["Name"]` as an array). MkDocs-style nested YAML is incompatible and will crash the build.
|
||||
16
ai/skills/go_expert/SKILL.md
Normal file
16
ai/skills/go_expert/SKILL.md
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
name: go_expert
|
||||
description: Google Go Style Guide Expert. Covers Style Guide, Style Decisions, and Best Practices.
|
||||
---
|
||||
# Go Expert
|
||||
|
||||
Expert in Google Go Style Guide.
|
||||
|
||||
## Core Mandate
|
||||
Follow the local style guide:
|
||||
- [Consolidated Style Guide](./STYLE_GUIDE.md)
|
||||
|
||||
## Key Principles
|
||||
- Simplicity and maintainability.
|
||||
- Standard libraries over third-party alternatives where possible.
|
||||
- Avoid complexity in APIs.
|
||||
5446
ai/skills/go_expert/STYLE_GUIDE.md
Normal file
5446
ai/skills/go_expert/STYLE_GUIDE.md
Normal file
File diff suppressed because it is too large
Load Diff
10
ai/skills/grill-me/SKILL.md
Normal file
10
ai/skills/grill-me/SKILL.md
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
name: grill-me
|
||||
description: Interview the user relentlessly about a plan or design until reaching shared understanding, resolving each branch of the decision tree. Use when user wants to stress-test a plan, get grilled on their design, or mentions "grill me".
|
||||
---
|
||||
|
||||
Interview me relentlessly about every aspect of this plan until we reach a shared understanding. Walk down each branch of the design tree, resolving dependencies between decisions one-by-one. For each question, provide your recommended answer.
|
||||
|
||||
Ask the questions one at a time.
|
||||
|
||||
If a question can be answered by exploring the codebase, explore the codebase instead.
|
||||
15
ai/skills/handoff/SKILL.md
Normal file
15
ai/skills/handoff/SKILL.md
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
name: handoff
|
||||
description: Compact the current conversation into a handoff document for another agent to pick up.
|
||||
argument-hint: "What will the next session be used for?"
|
||||
---
|
||||
|
||||
Write a handoff document summarising the current conversation so a fresh agent can continue the work. Save to the temporary directory of the user's OS - not the current workspace.
|
||||
|
||||
Include a "suggested skills" section in the document, which suggests skills that the agent should invoke.
|
||||
|
||||
Do not duplicate content already captured in other artifacts (PRDs, plans, ADRs, issues, commits, diffs). Reference them by path or URL instead.
|
||||
|
||||
Redact any sensitive information, such as API keys, passwords, or personally identifiable information.
|
||||
|
||||
If the user passed arguments, treat them as a description of what the next session will focus on and tailor the doc accordingly.
|
||||
15
ai/skills/html_css_expert/SKILL.md
Normal file
15
ai/skills/html_css_expert/SKILL.md
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
name: html_css_expert
|
||||
description: Google HTML/CSS Style Guide Expert. Use this for all web frontend structure and styling.
|
||||
---
|
||||
# HTML/CSS Expert
|
||||
|
||||
Expert in Google HTML/CSS Style Guide.
|
||||
|
||||
## Core Mandate
|
||||
Strictly follow [STYLE_GUIDE.md](./STYLE_GUIDE.md).
|
||||
|
||||
## Key Principles
|
||||
- Semantic HTML5.
|
||||
- Efficient CSS with minimal nesting.
|
||||
- Consistency in naming and formatting.
|
||||
668
ai/skills/html_css_expert/STYLE_GUIDE.md
Normal file
668
ai/skills/html_css_expert/STYLE_GUIDE.md
Normal file
@@ -0,0 +1,668 @@
|
||||
Google HTML/CSS Style Guide
|
||||
Table of Contents
|
||||
Background
|
||||
General
|
||||
General Style Rules
|
||||
General Formatting Rules
|
||||
General Meta Rules
|
||||
HTML
|
||||
HTML Style Rules
|
||||
HTML Formatting Rules
|
||||
CSS
|
||||
CSS Style Rules
|
||||
CSS Formatting Rules
|
||||
CSS Meta Rules
|
||||
Parting Words
|
||||
Background
|
||||
|
||||
This document defines formatting and style rules for HTML and CSS. It aims at improving collaboration, code quality, and enabling supporting infrastructure. It applies to raw, working files that use HTML and CSS, including Sass and GSS files. Tools are free to obfuscate, minify, and compile as long as the general code quality is maintained.
|
||||
|
||||
General
|
||||
General Style Rules
|
||||
Protocol
|
||||
|
||||
Use HTTPS for embedded resources where possible.
|
||||
|
||||
Always use HTTPS (https:) for images and other media files, style sheets, and scripts, unless the respective files are not available over HTTPS.
|
||||
|
||||
<!-- Not recommended: omits the protocol -->
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
|
||||
|
||||
<!-- Not recommended: uses HTTP -->
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
|
||||
<!-- Recommended -->
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
|
||||
/* Not recommended: omits the protocol */
|
||||
@import '//fonts.googleapis.com/css?family=Open+Sans';
|
||||
|
||||
/* Not recommended: uses HTTP */
|
||||
@import 'http://fonts.googleapis.com/css?family=Open+Sans';
|
||||
/* Recommended */
|
||||
@import 'https://fonts.googleapis.com/css?family=Open+Sans';
|
||||
General Formatting Rules
|
||||
Indentation
|
||||
|
||||
Indent by 2 spaces at a time.
|
||||
|
||||
Don’t use tabs or mix tabs and spaces for indentation.
|
||||
|
||||
<ul>
|
||||
<li>Fantastic
|
||||
<li>Great
|
||||
</ul>
|
||||
.example {
|
||||
color: blue;
|
||||
}
|
||||
Capitalization
|
||||
|
||||
Use only lowercase.
|
||||
|
||||
All code has to be lowercase: This applies to HTML element names, attributes, attribute values (unless text/CDATA), CSS selectors, properties, and property values (with the exception of strings).
|
||||
|
||||
<!-- Not recommended -->
|
||||
<A HREF="/">Home</A>
|
||||
<!-- Recommended -->
|
||||
<img src="google.png" alt="Google">
|
||||
/* Not recommended */
|
||||
color: #E5E5E5;
|
||||
/* Recommended */
|
||||
color: #e5e5e5;
|
||||
Trailing Whitespace
|
||||
|
||||
Remove trailing white spaces.
|
||||
|
||||
Trailing white spaces are unnecessary and can complicate diffs.
|
||||
|
||||
<!-- Not recommended -->
|
||||
<p>What?_
|
||||
<!-- Recommended -->
|
||||
<p>Yes please.
|
||||
General Meta Rules
|
||||
Encoding
|
||||
|
||||
Use UTF-8 (no BOM).
|
||||
|
||||
Make sure your editor uses UTF-8 as character encoding, without a byte order mark.
|
||||
|
||||
Specify the encoding in HTML templates and documents via <meta charset="utf-8">. Do not specify the encoding of style sheets as these assume UTF-8.
|
||||
|
||||
(More on encodings and when and how to specify them can be found in Handling character encodings in HTML and CSS.)
|
||||
|
||||
Comments
|
||||
|
||||
Explain code as needed, where possible.
|
||||
|
||||
Use comments to explain code: What does it cover, what purpose does it serve, why is respective solution used or preferred?
|
||||
|
||||
(This item is optional as it is not deemed a realistic expectation to always demand fully documented code. Mileage may vary heavily for HTML and CSS code and depends on the project’s complexity.)
|
||||
|
||||
Action Items
|
||||
|
||||
Mark todos and action items with TODO.
|
||||
|
||||
Highlight todos by using the keyword TODO only, not other common formats like @@.
|
||||
|
||||
Append action items after a colon as in TODO: action item.
|
||||
|
||||
{# TODO: Revisit centering. #}
|
||||
<center>Test</center>
|
||||
<!-- TODO: Remove optional tags. -->
|
||||
<ul>
|
||||
<li>Apples</li>
|
||||
<li>Oranges</li>
|
||||
</ul>
|
||||
HTML
|
||||
HTML Style Rules
|
||||
Document Type
|
||||
|
||||
Use <!doctype html>.
|
||||
|
||||
Always put your HTML in no-quirks mode by including <!doctype html> at the beginning of the document.
|
||||
|
||||
A document without a doctype is rendered in “quirks mode”, and one with a different doctype may be rendered in “limited-quirks mode”. These modes don’t follow the widely-understood, widely-documented behavior for various core HTML and CSS constructs, and are likely to cause subtle failures and incompatibilities especially when re-using code that expects no-quirks mode.
|
||||
|
||||
HTML Validity
|
||||
|
||||
Use valid HTML where possible.
|
||||
|
||||
Use valid HTML code unless that is not possible due to otherwise unattainable performance goals regarding file size.
|
||||
|
||||
Use tools such as the W3C HTML validator to test.
|
||||
|
||||
Using valid HTML is a measurable baseline quality attribute that contributes to learning about technical requirements and constraints, and that ensures proper HTML usage.
|
||||
|
||||
<!-- Not recommended -->
|
||||
<title>Test</title>
|
||||
<article>This is only a test.
|
||||
<!-- Recommended -->
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>Test</title>
|
||||
<article>This is only a test.</article>
|
||||
Semantics
|
||||
|
||||
Use HTML according to its purpose.
|
||||
|
||||
Use elements (sometimes incorrectly called “tags”) for what they have been created for. For example, use heading elements for headings, p elements for paragraphs, a elements for anchors, etc.
|
||||
|
||||
Using HTML according to its purpose is important for accessibility, reuse, and code efficiency reasons.
|
||||
|
||||
<!-- Not recommended -->
|
||||
<div onclick="goToRecommendations();">All recommendations</div>
|
||||
<!-- Recommended -->
|
||||
<a href="recommendations/">All recommendations</a>
|
||||
Multimedia Fallback
|
||||
|
||||
Provide alternative contents for multimedia.
|
||||
|
||||
For multimedia, such as images, videos, animated objects via canvas, make sure to offer alternative access. For images that means use of meaningful alternative text (alt) and for video and audio transcripts and captions, if available.
|
||||
|
||||
Providing alternative contents is important for accessibility reasons: A blind user has few cues to tell what an image is about without @alt, and other users may have no way of understanding what video or audio contents are about either.
|
||||
|
||||
(For images whose alt attributes would introduce redundancy, and for images whose purpose is purely decorative which you cannot immediately use CSS for, use no alternative text, as in alt="".)
|
||||
|
||||
<!-- Not recommended -->
|
||||
<img src="spreadsheet.png">
|
||||
<!-- Recommended -->
|
||||
<img src="spreadsheet.png" alt="Spreadsheet screenshot.">
|
||||
Separation of Concerns
|
||||
|
||||
Separate structure from presentation from behavior.
|
||||
|
||||
Strictly keep structure (markup), presentation (styling), and behavior (scripting) apart, and try to keep the interaction between the three to an absolute minimum.
|
||||
|
||||
That is, make sure documents and templates contain only HTML and HTML that is solely serving structural purposes. Move everything presentational into style sheets, and everything behavioral into scripts.
|
||||
|
||||
In addition, keep the contact area as small as possible by linking as few style sheets and scripts as possible from documents and templates.
|
||||
|
||||
Separating structure from presentation from behavior is important for maintenance reasons. It is always more expensive to change HTML documents and templates than it is to update style sheets and scripts.
|
||||
|
||||
<!-- Not recommended -->
|
||||
<!doctype html>
|
||||
<title>HTML sucks</title>
|
||||
<link rel="stylesheet" href="base.css" media="screen">
|
||||
<link rel="stylesheet" href="grid.css" media="screen">
|
||||
<link rel="stylesheet" href="print.css" media="print">
|
||||
<h1 style="font-size: 1em;">HTML sucks</h1>
|
||||
<p>I’ve read about this on a few sites but now I’m sure:
|
||||
<u>HTML is stupid!!1</u>
|
||||
<center>I can’t believe there’s no way to control the styling of
|
||||
my website without doing everything all over again!</center>
|
||||
<!-- Recommended -->
|
||||
<!doctype html>
|
||||
<title>My first CSS-only redesign</title>
|
||||
<link rel="stylesheet" href="default.css">
|
||||
<h1>My first CSS-only redesign</h1>
|
||||
<p>I’ve read about this on a few sites but today I’m actually
|
||||
doing it: separating concerns and avoiding anything in the HTML of
|
||||
my website that is presentational.
|
||||
<p>It’s awesome!
|
||||
Entity References
|
||||
|
||||
Do not use entity references.
|
||||
|
||||
There is no need to use entity references like —, ”, or ☺, assuming the same encoding (UTF-8) is used for files and editors as well as among teams.
|
||||
|
||||
The only exceptions apply to characters with special meaning in HTML (like < and &) as well as control or “invisible” characters (like no-break spaces).
|
||||
|
||||
<!-- Not recommended -->
|
||||
The currency symbol for the Euro is “&eur;”.
|
||||
<!-- Recommended -->
|
||||
The currency symbol for the Euro is “€”.
|
||||
Optional Tags
|
||||
|
||||
Omit optional tags (optional).
|
||||
|
||||
For file size optimization and scannability purposes, consider omitting optional tags. The HTML5 specification defines what tags can be omitted.
|
||||
|
||||
(This approach may require a grace period to be established as a wider guideline as it’s significantly different from what web developers are typically taught. For consistency and simplicity reasons it’s best served omitting all optional tags, not just a selection.)
|
||||
|
||||
<!-- Not recommended -->
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Spending money, spending bytes</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Sic.</p>
|
||||
</body>
|
||||
</html>
|
||||
<!-- Recommended -->
|
||||
<!doctype html>
|
||||
<title>Saving money, saving bytes</title>
|
||||
<p>Qed.
|
||||
type Attributes
|
||||
|
||||
Omit type attributes for style sheets and scripts.
|
||||
|
||||
Do not use type attributes for style sheets (unless not using CSS) and scripts (unless not using JavaScript).
|
||||
|
||||
Specifying type attributes in these contexts is not necessary as HTML5 implies text/css and text/javascript as defaults. This can be safely done even for older browsers.
|
||||
|
||||
<!-- Not recommended -->
|
||||
<link rel="stylesheet" href="https://www.google.com/css/maia.css"
|
||||
type="text/css">
|
||||
<!-- Recommended -->
|
||||
<link rel="stylesheet" href="https://www.google.com/css/maia.css">
|
||||
<!-- Not recommended -->
|
||||
<script src="https://www.google.com/js/gweb/analytics/autotrack.js"
|
||||
type="text/javascript"></script>
|
||||
<!-- Recommended -->
|
||||
<script src="https://www.google.com/js/gweb/analytics/autotrack.js"></script>
|
||||
id Attributes
|
||||
|
||||
Avoid unnecessary id attributes.
|
||||
|
||||
Prefer class attributes for styling and data attributes for scripting.
|
||||
|
||||
Where id attributes are strictly required, always include a hyphen in the value to ensure it does not match the JavaScript identifier syntax, e.g. use user-profile rather than just profile or userProfile.
|
||||
|
||||
When an element has an id attribute, browsers will make that available as a named property on the global window prototype, which may cause unexpected behavior. While id attribute values containing a hyphen are still available as property names, these cannot be referenced as global JavaScript variables.
|
||||
|
||||
<!-- Not recommended: `window.userProfile` will resolve to reference the <div> node -->
|
||||
<div id="userProfile"></div>
|
||||
<!-- Recommended: `id` attribute is required and its value includes a hyphen -->
|
||||
<div aria-describedby="user-profile">
|
||||
…
|
||||
<div id="user-profile"></div>
|
||||
…
|
||||
</div>
|
||||
HTML Formatting Rules
|
||||
General Formatting
|
||||
|
||||
Use a new line for every block, list, or table element, and indent every such child element.
|
||||
|
||||
Independent of the styling of an element (as CSS allows elements to assume a different role per display property), put every block, list, or table element on a new line.
|
||||
|
||||
Also, indent them if they are child elements of a block, list, or table element.
|
||||
|
||||
(If you run into issues around whitespace between list items it’s acceptable to put all li elements in one line. A linter is encouraged to throw a warning instead of an error.)
|
||||
|
||||
<blockquote>
|
||||
<p><em>Space</em>, the final frontier.</p>
|
||||
</blockquote>
|
||||
<ul>
|
||||
<li>Moe
|
||||
<li>Larry
|
||||
<li>Curly
|
||||
</ul>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Income
|
||||
<th scope="col">Taxes
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>$ 5.00
|
||||
<td>$ 4.50
|
||||
</table>
|
||||
HTML Line-Wrapping
|
||||
|
||||
Break long lines (optional).
|
||||
|
||||
While there is no column limit recommendation for HTML, you may consider wrapping long lines if it significantly improves readability.
|
||||
|
||||
When line-wrapping, each continuation line should be indented to distinguish wrapped attributes from child elements. Lines should be wrapped consistently within a project, ideally enforced by automated code formatting tools.
|
||||
|
||||
<button
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
class="menu-button"
|
||||
(click)="openMenu()"
|
||||
>
|
||||
<mat-icon>menu</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button color="primary" class="menu-button"
|
||||
(click)="openMenu()">
|
||||
<mat-icon>menu</mat-icon>
|
||||
</button>
|
||||
<button
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
class="menu-button"
|
||||
(click)="openMenu()">
|
||||
<mat-icon>menu</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button
|
||||
color="primary"
|
||||
class="menu-button"
|
||||
(click)="openMenu()">
|
||||
<mat-icon>menu</mat-icon>
|
||||
</button>
|
||||
HTML Quotation Marks
|
||||
|
||||
When quoting attributes values, use double quotation marks.
|
||||
|
||||
Use double ("") rather than single quotation marks ('') around attribute values.
|
||||
|
||||
<!-- Not recommended -->
|
||||
<a class='maia-button maia-button-secondary'>Sign in</a>
|
||||
<!-- Recommended -->
|
||||
<a class="maia-button maia-button-secondary">Sign in</a>
|
||||
CSS
|
||||
CSS Style Rules
|
||||
CSS Validity
|
||||
|
||||
Use valid CSS where possible.
|
||||
|
||||
Unless dealing with CSS validator bugs or requiring proprietary syntax, use valid CSS code.
|
||||
|
||||
Use tools such as the W3C CSS validator to test.
|
||||
|
||||
Using valid CSS is a measurable baseline quality attribute that allows to spot CSS code that may not have any effect and can be removed, and that ensures proper CSS usage.
|
||||
|
||||
Class Naming
|
||||
|
||||
Use meaningful or generic class names.
|
||||
|
||||
Instead of presentational or cryptic names, always use class names that reflect the purpose of the element in question, or that are otherwise generic.
|
||||
|
||||
Names that are specific and reflect the purpose of the element should be preferred as these are most understandable and the least likely to change.
|
||||
|
||||
Generic names are simply a fallback for elements that have no particular or no meaning different from their siblings. They are typically needed as “helpers.”
|
||||
|
||||
Using functional or generic names reduces the probability of unnecessary document or template changes.
|
||||
|
||||
/* Not recommended: meaningless */
|
||||
.yee-1901 {}
|
||||
|
||||
/* Not recommended: presentational */
|
||||
.button-green {}
|
||||
.clear {}
|
||||
/* Recommended: specific */
|
||||
.gallery {}
|
||||
.login {}
|
||||
.video {}
|
||||
|
||||
/* Recommended: generic */
|
||||
.aux {}
|
||||
.alt {}
|
||||
Class Name Style
|
||||
|
||||
Use class names that are as short as possible but as long as necessary.
|
||||
|
||||
Try to convey what a class is about while being as brief as possible.
|
||||
|
||||
Using class names this way contributes to acceptable levels of understandability and code efficiency.
|
||||
|
||||
/* Not recommended */
|
||||
.navigation {}
|
||||
.atr {}
|
||||
/* Recommended */
|
||||
.nav {}
|
||||
.author {}
|
||||
Class Name Delimiters
|
||||
|
||||
Separate words in class names by a hyphen.
|
||||
|
||||
Do not concatenate words and abbreviations in selectors by any characters (including none at all) other than hyphens, in order to improve understanding and scannability.
|
||||
|
||||
/* Not recommended: does not separate the words “demo” and “image” */
|
||||
.demoimage {}
|
||||
|
||||
/* Not recommended: uses underscore instead of hyphen */
|
||||
.error_status {}
|
||||
/* Recommended */
|
||||
.video-id {}
|
||||
.ads-sample {}
|
||||
Prefixes
|
||||
|
||||
Prefix selectors with an application-specific prefix (optional).
|
||||
|
||||
In large projects as well as for code that gets embedded in other projects or on external sites use prefixes (as namespaces) for class names. Use short, unique identifiers followed by a dash.
|
||||
|
||||
Using namespaces helps preventing naming conflicts and can make maintenance easier, for example in search and replace operations.
|
||||
|
||||
.adw-help {} /* AdWords */
|
||||
.maia-note {} /* Maia */
|
||||
Type Selectors
|
||||
|
||||
Avoid qualifying class names with type selectors.
|
||||
|
||||
Unless necessary (for example with helper classes), do not use element names in conjunction with classes.
|
||||
|
||||
Avoiding unnecessary ancestor selectors is useful for performance reasons.
|
||||
|
||||
/* Not recommended */
|
||||
ul.example {}
|
||||
div.error {}
|
||||
/* Recommended */
|
||||
.example {}
|
||||
.error {}
|
||||
ID Selectors
|
||||
|
||||
Avoid ID selectors.
|
||||
|
||||
ID attributes are expected to be unique across an entire page, which is difficult to guarantee when a page contains many components worked on by many different engineers. Class selectors should be preferred in all situations.
|
||||
|
||||
/* Not recommended */
|
||||
#example {}
|
||||
/* Recommended */
|
||||
.example {}
|
||||
Shorthand Properties
|
||||
|
||||
Use shorthand properties where possible.
|
||||
|
||||
CSS offers a variety of shorthand properties (like font) that should be used whenever possible, even in cases where only one value is explicitly set.
|
||||
|
||||
Using shorthand properties is useful for code efficiency and understandability.
|
||||
|
||||
/* Not recommended */
|
||||
border-top-style: none;
|
||||
font-family: palatino, georgia, serif;
|
||||
font-size: 100%;
|
||||
line-height: 1.6;
|
||||
padding-bottom: 2em;
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
padding-top: 0;
|
||||
/* Recommended */
|
||||
border-top: 0;
|
||||
font: 100%/1.6 palatino, georgia, serif;
|
||||
padding: 0 1em 2em;
|
||||
0 and Units
|
||||
|
||||
Omit unit specification after “0” values, unless required.
|
||||
|
||||
Do not use units after 0 values unless they are required.
|
||||
|
||||
flex: 0px; /* This flex-basis component requires a unit. */
|
||||
flex: 1 1 0px; /* Not ambiguous without the unit, but needed in IE11. */
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
Leading 0s
|
||||
|
||||
Always include leading “0”s in values.
|
||||
|
||||
Put 0s in front of values or lengths between -1 and 1.
|
||||
|
||||
font-size: 0.8em;
|
||||
Hexadecimal Notation
|
||||
|
||||
Use 3 character hexadecimal notation where possible.
|
||||
|
||||
For color values that permit it, 3 character hexadecimal notation is shorter and more succinct.
|
||||
|
||||
/* Not recommended */
|
||||
color: #eebbcc;
|
||||
/* Recommended */
|
||||
color: #ebc;
|
||||
Important Declarations
|
||||
|
||||
Avoid using !important declarations.
|
||||
|
||||
These declarations break the natural cascade of CSS and make it difficult to reason about and compose styles. Use selector specificity to override properties instead.
|
||||
|
||||
/* Not recommended */
|
||||
.example {
|
||||
font-weight: bold !important;
|
||||
}
|
||||
/* Recommended */
|
||||
.example {
|
||||
font-weight: bold;
|
||||
}
|
||||
Hacks
|
||||
|
||||
Avoid user agent detection as well as CSS “hacks”—try a different approach first.
|
||||
|
||||
It’s tempting to address styling differences over user agent detection or special CSS filters, workarounds, and hacks. Both approaches should be considered last resort in order to achieve and maintain an efficient and manageable code base. Put another way, giving detection and hacks a free pass will hurt projects in the long run as projects tend to take the way of least resistance. That is, allowing and making it easy to use detection and hacks means using detection and hacks more frequently—and more frequently is too frequently.
|
||||
|
||||
CSS Formatting Rules
|
||||
Declaration Order
|
||||
|
||||
Alphabetize declarations (optional).
|
||||
|
||||
Sort declarations consistently within a project. In the absence of tooling to automate and enforce a consistent sort order, consider putting declarations in alphabetical order in order to achieve consistent code in a way that is easy to learn, remember, and manually maintain.
|
||||
|
||||
Ignore vendor-specific prefixes for sorting purposes. However, multiple vendor-specific prefixes for a certain CSS property should be kept sorted (e.g. -moz prefix comes before -webkit).
|
||||
|
||||
background: fuchsia;
|
||||
border: 1px solid;
|
||||
-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
color: black;
|
||||
text-align: center;
|
||||
text-indent: 2em;
|
||||
Block Content Indentation
|
||||
|
||||
Indent all block content.
|
||||
|
||||
Indent all block content, that is rules within rules as well as declarations, so to reflect hierarchy and improve understanding.
|
||||
|
||||
@media screen, projection {
|
||||
|
||||
html {
|
||||
background: #fff;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
}
|
||||
Declaration Stops
|
||||
|
||||
Use a semicolon after every declaration.
|
||||
|
||||
End every declaration with a semicolon for consistency and extensibility reasons.
|
||||
|
||||
/* Not recommended */
|
||||
.test {
|
||||
display: block;
|
||||
height: 100px
|
||||
}
|
||||
/* Recommended */
|
||||
.test {
|
||||
display: block;
|
||||
height: 100px;
|
||||
}
|
||||
Property Name Stops
|
||||
|
||||
Use a space after a property name’s colon.
|
||||
|
||||
Always use a single space between property and value (but no space between property and colon) for consistency reasons.
|
||||
|
||||
/* Not recommended */
|
||||
h3 {
|
||||
font-weight:bold;
|
||||
}
|
||||
/* Recommended */
|
||||
h3 {
|
||||
font-weight: bold;
|
||||
}
|
||||
Declaration Block Separation
|
||||
|
||||
Use a space between the last selector and the declaration block.
|
||||
|
||||
Always use a single space between the last selector and the opening brace that begins the declaration block.
|
||||
|
||||
The opening brace should be on the same line as the last selector in a given rule.
|
||||
|
||||
/* Not recommended: missing space */
|
||||
.video{
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
/* Not recommended: unnecessary line break */
|
||||
.video
|
||||
{
|
||||
margin-top: 1em;
|
||||
}
|
||||
/* Recommended */
|
||||
.video {
|
||||
margin-top: 1em;
|
||||
}
|
||||
Selector and Declaration Separation
|
||||
|
||||
Separate selectors and declarations by new lines.
|
||||
|
||||
Always start a new line for each selector and declaration.
|
||||
|
||||
/* Not recommended */
|
||||
a:focus, a:active {
|
||||
position: relative; top: 1px;
|
||||
}
|
||||
/* Recommended */
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
font-weight: normal;
|
||||
line-height: 1.2;
|
||||
}
|
||||
Rule Separation
|
||||
|
||||
Separate rules by new lines.
|
||||
|
||||
Always put a blank line (two line breaks) between rules.
|
||||
|
||||
html {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: auto;
|
||||
width: 50%;
|
||||
}
|
||||
CSS Quotation Marks
|
||||
|
||||
Use single ('') rather than double ("") quotation marks for attribute selectors and property values.
|
||||
|
||||
Do not use quotation marks in URI values (url()).
|
||||
|
||||
Exception: If you do need to use the @charset rule, use double quotation marks—single quotation marks are not permitted.
|
||||
|
||||
/* Not recommended */
|
||||
@import url("https://www.google.com/css/maia.css");
|
||||
|
||||
html {
|
||||
font-family: "open sans", arial, sans-serif;
|
||||
}
|
||||
/* Recommended */
|
||||
@import url(https://www.google.com/css/maia.css);
|
||||
|
||||
html {
|
||||
font-family: 'open sans', arial, sans-serif;
|
||||
}
|
||||
CSS Meta Rules
|
||||
Section Comments
|
||||
|
||||
Group sections by a section comment (optional).
|
||||
|
||||
If possible, group style sheet sections together by using comments. Separate sections with new lines.
|
||||
|
||||
/* Header */
|
||||
|
||||
.adw-header {}
|
||||
|
||||
/* Footer */
|
||||
|
||||
.adw-footer {}
|
||||
|
||||
/* Gallery */
|
||||
|
||||
.adw-gallery {}
|
||||
Parting Words
|
||||
|
||||
Be consistent.
|
||||
|
||||
If you’re editing code, take a few minutes to look at the code around you and determine its style. If they use spaces around all their arithmetic operators, you should too. If their comments have little boxes of hash marks around them, make your comments have little boxes of hash marks around them too.
|
||||
|
||||
The point of having style guidelines is to have a common vocabulary of coding so people can concentrate on what you’re saying rather than on how you’re saying it. We present global style rules here so people know the vocabulary, but local style is also important. If code you add to a file looks drastically different from the existing code around it, it throws readers out of their rhythm when they go to read it. Avoid this.
|
||||
15
ai/skills/java_expert/SKILL.md
Normal file
15
ai/skills/java_expert/SKILL.md
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
name: java_expert
|
||||
description: Google Java Style Guide Expert. Follows official Google Java coding standards.
|
||||
---
|
||||
# Java Expert
|
||||
|
||||
Expert in Google Java Style Guide.
|
||||
|
||||
## Core Mandate
|
||||
Strictly follow [STYLE_GUIDE.md](./STYLE_GUIDE.md).
|
||||
|
||||
## Key Principles
|
||||
- Clean class hierarchies.
|
||||
- Effective use of annotations and generics.
|
||||
- Proper exception handling and logging.
|
||||
779
ai/skills/java_expert/STYLE_GUIDE.md
Normal file
779
ai/skills/java_expert/STYLE_GUIDE.md
Normal file
@@ -0,0 +1,779 @@
|
||||
Google Java Style Guide
|
||||
Table of Contents
|
||||
1 Introduction
|
||||
1.1 Terminology notes
|
||||
1.2 Guide notes
|
||||
2 Source file basics
|
||||
2.1 File name
|
||||
2.2 File encoding: UTF-8
|
||||
2.3 Special characters
|
||||
3 Source file structure
|
||||
3.1 License or copyright information, if present
|
||||
3.2 Package declaration
|
||||
3.3 Imports
|
||||
3.4 Class declaration
|
||||
3.5 Module declaration
|
||||
4 Formatting
|
||||
4.1 Braces
|
||||
4.2 Block indentation: +2 spaces
|
||||
4.3 One statement per line
|
||||
4.4 Column limit: 100
|
||||
4.5 Line-wrapping
|
||||
4.6 Whitespace
|
||||
4.7 Grouping parentheses: recommended
|
||||
4.8 Specific constructs
|
||||
5 Naming
|
||||
5.1 Rules common to all identifiers
|
||||
5.2 Rules by identifier type
|
||||
5.3 Camel case: defined
|
||||
6 Programming Practices
|
||||
6.1 @Override: always used
|
||||
6.2 Caught exceptions: not ignored
|
||||
6.3 Static members: qualified using class
|
||||
6.4 Finalizers: not used
|
||||
7 Javadoc
|
||||
7.1 Formatting
|
||||
7.2 The summary fragment
|
||||
7.3 Where Javadoc is used
|
||||
1 Introduction
|
||||
|
||||
This document serves as the complete definition of Google's coding standards for source code in the Java™ Programming Language. A Java source file is described as being in Google Style if and only if it adheres to the rules herein.
|
||||
|
||||
Like other programming style guides, the issues covered span not only aesthetic issues of formatting, but other types of conventions or coding standards as well. However, this document focuses primarily on the hard-and-fast rules that we follow universally, and avoids giving advice that isn't clearly enforceable (whether by human or tool).
|
||||
|
||||
1.1 Terminology notes
|
||||
|
||||
In this document, unless otherwise clarified:
|
||||
|
||||
The term class is used inclusively to mean a normal class, record class, enum class, interface or annotation type (@interface).
|
||||
The term member (of a class) is used inclusively to mean a nested class, field, method, or constructor; that is, all top-level contents of a class except initializers.
|
||||
The term comment always refers to implementation comments. We do not use the phrase "documentation comments", and instead use the common term "Javadoc."
|
||||
|
||||
Other "terminology notes" will appear occasionally throughout the document.
|
||||
|
||||
1.2 Guide notes
|
||||
|
||||
Example code in this document is non-normative. That is, while the examples are in Google Style, they may not illustrate the only stylish way to represent the code. Optional formatting choices made in examples should not be enforced as rules.
|
||||
|
||||
2 Source file basics
|
||||
2.1 File name
|
||||
|
||||
For a source file containing classes, the file name consists of the case-sensitive name of the top-level class (of which there is exactly one), plus the .java extension.
|
||||
|
||||
2.2 File encoding: UTF-8
|
||||
|
||||
Source files are encoded in UTF-8.
|
||||
|
||||
2.3 Special characters
|
||||
2.3.1 Whitespace characters
|
||||
|
||||
Aside from the line terminator sequence, the ASCII horizontal space character (0x20) is the only whitespace character that appears anywhere in a source file. This implies that:
|
||||
|
||||
All other whitespace characters are escaped in char and string literals and in text blocks.
|
||||
Tab characters are not used for indentation.
|
||||
2.3.2 Special escape sequences
|
||||
|
||||
For any character that has a special escape sequence (\b, \t, \n, \f, \r, \s, \", \' and \\), that sequence is used rather than the corresponding octal (e.g. \012) or Unicode (e.g. \u000a) escape.
|
||||
|
||||
2.3.3 Non-ASCII characters
|
||||
|
||||
For the remaining non-ASCII characters, either the actual Unicode character (e.g. ∞) or the equivalent Unicode escape (e.g. \u221e) is used. The choice depends only on which makes the code easier to read and understand, although Unicode escapes outside string literals and comments are strongly discouraged.
|
||||
|
||||
Tip: In the Unicode escape case, and occasionally even when actual Unicode characters are used, an explanatory comment can be very helpful.
|
||||
|
||||
Examples:
|
||||
|
||||
Example Discussion
|
||||
String unitAbbrev = "μs"; Best: perfectly clear even without a comment.
|
||||
String unitAbbrev = "\u03bcs"; // "μs" Allowed, but there's no reason to do this.
|
||||
String unitAbbrev = "\u03bcs"; // Greek letter mu, "s" Allowed, but awkward and prone to mistakes.
|
||||
String unitAbbrev = "\u03bcs"; Poor: the reader has no idea what this is.
|
||||
return '\ufeff' + content; // byte order mark Good: use escapes for non-printable characters, and comment if necessary.
|
||||
|
||||
Tip: Never make your code less readable simply out of fear that some programs might not handle non-ASCII characters properly. If that should happen, those programs are broken and they must be fixed.
|
||||
|
||||
3 Source file structure
|
||||
|
||||
An ordinary source file consists of these sections, in order:
|
||||
|
||||
License or copyright information, if present
|
||||
Package declaration
|
||||
Imports
|
||||
Exactly one top-level class declaration
|
||||
|
||||
Exactly one blank line separates each section that is present.
|
||||
|
||||
A package-info.java file is the same, but without the class declaration.
|
||||
|
||||
A module-info.java file does not contain a package declaration and replaces the class declaration with a module declaration, but otherwise follows the same structure.
|
||||
|
||||
3.1 License or copyright information, if present
|
||||
|
||||
If license or copyright information belongs in a file, it belongs here.
|
||||
|
||||
3.2 Package declaration
|
||||
|
||||
The package declaration is not line-wrapped. The column limit (Section 4.4, Column limit: 100) does not apply to package declarations.
|
||||
|
||||
3.3 Imports
|
||||
3.3.1 No wildcard imports
|
||||
|
||||
Wildcard ("on-demand") imports, static or otherwise, are not used.
|
||||
|
||||
3.3.2 No line-wrapping
|
||||
|
||||
Imports are not line-wrapped. The column limit (Section 4.4, Column limit: 100) does not apply to imports.
|
||||
|
||||
3.3.3 Ordering and spacing
|
||||
|
||||
Imports are ordered as follows:
|
||||
|
||||
All static imports in a single group.
|
||||
All non-static imports in a single group.
|
||||
|
||||
If there are both static and non-static imports, a single blank line separates the two groups. There are no other blank lines between imports.
|
||||
|
||||
Within each group the imported names appear in ASCII sort order. (Note: this is not the same as the import lines being in ASCII sort order, since '.' sorts before ';'.)
|
||||
|
||||
3.3.4 No static import for classes
|
||||
|
||||
Static import is not used for static nested classes. They are imported with normal imports.
|
||||
|
||||
3.4 Class declaration
|
||||
3.4.1 Exactly one top-level class declaration
|
||||
|
||||
Each top-level class resides in a source file of its own.
|
||||
|
||||
3.4.2 Ordering of class contents
|
||||
|
||||
The order you choose for the members and initializers of your class can have a great effect on learnability. However, there's no single correct recipe for how to do it; different classes may order their contents in different ways.
|
||||
|
||||
What is important is that each class uses some logical order, which its maintainer could explain if asked. For example, new methods are not just habitually added to the end of the class, as that would yield "chronological by date added" ordering, which is not a logical ordering.
|
||||
|
||||
3.4.2.1 Overloads: never split
|
||||
|
||||
Methods of a class that share the same name appear in a single contiguous group with no other members in between. The same applies to multiple constructors. This rule applies even when modifiers such as static or private differ between the methods or constructors.
|
||||
|
||||
3.5 Module declaration
|
||||
3.5.1 Ordering and spacing of module directives
|
||||
|
||||
Module directives are ordered as follows:
|
||||
|
||||
All requires directives in a single block.
|
||||
All exports directives in a single block.
|
||||
All opens directives in a single block.
|
||||
All uses directives in a single block.
|
||||
All provides directives in a single block.
|
||||
|
||||
A single blank line separates each block that is present.
|
||||
|
||||
4 Formatting
|
||||
|
||||
Terminology Note: block-like construct refers to the body of a class, method, constructor, or switch. Note that, by Section 4.8.3.1 on array initializers, any array initializer may optionally be treated as if it were a block-like construct.
|
||||
|
||||
4.1 Braces
|
||||
4.1.1 Use of optional braces
|
||||
|
||||
Braces are used with if, else, for, do and while statements, even when the body is empty or contains only a single statement.
|
||||
|
||||
Other optional braces, such as those in a lambda expression, remain optional.
|
||||
|
||||
4.1.2 Nonempty blocks: K & R style
|
||||
|
||||
Braces follow the Kernighan and Ritchie style for nonempty blocks and block-like constructs:
|
||||
|
||||
No line break before the opening brace, except as detailed below.
|
||||
Line break after the opening brace.
|
||||
Line break before the closing brace.
|
||||
Line break after the closing brace, only if that brace terminates a statement or terminates the body of a method, constructor, or named class. For example, there is no line break after the brace if it is followed by else or a comma.
|
||||
|
||||
Exception: In places where these rules allow a single statement ending with a semicolon (;), a block of statements can appear, and the opening brace of this block is preceded by a line break. Blocks like these are typically introduced to limit the scope of local variables.
|
||||
|
||||
Examples:
|
||||
|
||||
return () -> {
|
||||
while (condition()) {
|
||||
method();
|
||||
}
|
||||
};
|
||||
|
||||
return new MyClass() {
|
||||
@Override public void method() {
|
||||
if (condition()) {
|
||||
try {
|
||||
something();
|
||||
} catch (ProblemException e) {
|
||||
recover();
|
||||
}
|
||||
} else if (otherCondition()) {
|
||||
somethingElse();
|
||||
} else {
|
||||
lastThing();
|
||||
}
|
||||
{
|
||||
int x = foo();
|
||||
frob(x);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
A few exceptions for enum classes are given in Section 4.8.1, Enum classes.
|
||||
|
||||
4.1.3 Empty blocks: may be concise
|
||||
|
||||
An empty block or block-like construct may be in K & R style (as described in Section 4.1.2). Alternatively, it may be closed immediately after it is opened, with no characters or line break in between ({}), unless it is part of a multi-block statement (one that directly contains multiple blocks: if/else or try/catch/finally).
|
||||
|
||||
Examples:
|
||||
|
||||
// This is acceptable
|
||||
void doNothing() {}
|
||||
|
||||
// This is equally acceptable
|
||||
void doNothingElse() {
|
||||
}
|
||||
// This is not acceptable: No concise empty blocks in a multi-block statement
|
||||
try {
|
||||
doSomething();
|
||||
} catch (Exception e) {}
|
||||
4.2 Block indentation: +2 spaces
|
||||
|
||||
Each time a new block or block-like construct is opened, the indent increases by two spaces. When the block ends, the indent returns to the previous indent level. The indent level applies to both code and comments throughout the block. (See the example in Section 4.1.2, Nonempty blocks: K & R Style.)
|
||||
|
||||
4.3 One statement per line
|
||||
|
||||
Each statement is followed by a line break.
|
||||
|
||||
4.4 Column limit: 100
|
||||
|
||||
Java code has a column limit of 100 characters. A "character" means any Unicode code point. Except as noted below, any line that would exceed this limit must be line-wrapped, as explained in Section 4.5, Line-wrapping.
|
||||
|
||||
Each Unicode code point counts as one character, even if its display width is greater or less. For example, if using fullwidth characters, you may choose to wrap the line earlier than where this rule strictly requires.
|
||||
|
||||
Exceptions:
|
||||
|
||||
Lines where obeying the column limit is not possible (for example, a long URL in Javadoc, or a long JSNI method reference).
|
||||
package declarations and imports (see Sections 3.2 Package declarations and 3.3 Imports).
|
||||
Contents of text blocks.
|
||||
Command lines in a comment that may be copied-and-pasted into a shell.
|
||||
Very long identifiers, on the rare occasions they are called for, are allowed to exceed the column limit. In that case, the valid wrapping for the surrounding code is as produced by google-java-format.
|
||||
4.5 Line-wrapping
|
||||
|
||||
Terminology Note: When code that might otherwise occupy a single line is divided into multiple lines, this activity is called line-wrapping.
|
||||
|
||||
There is no comprehensive, deterministic formula showing exactly how to line-wrap in every situation. Very often there are several valid ways to line-wrap the same piece of code.
|
||||
|
||||
Note: While the typical reason for line-wrapping is to avoid overflowing the column limit, even code that would in fact fit within the column limit may be line-wrapped at the author's discretion.
|
||||
|
||||
Tip: Extracting a method or local variable may solve the problem without the need to line-wrap.
|
||||
|
||||
4.5.1 Where to break
|
||||
|
||||
The prime directive of line-wrapping is: prefer to break at a higher syntactic level. Also:
|
||||
|
||||
When a line is broken at a non-assignment operator the break comes before the symbol. (Note that this is not the same practice used in Google style for other languages, such as C++ and JavaScript.)
|
||||
This also applies to the following "operator-like" symbols:
|
||||
the dot separator (.)
|
||||
the two colons of a method reference (::)
|
||||
an ampersand in a type bound (<T extends Foo & Bar>)
|
||||
a pipe in a catch block (catch (FooException | BarException e)).
|
||||
When a line is broken at an assignment operator the break typically comes after the symbol, but either way is acceptable.
|
||||
This also applies to the colon in an enhanced for ("foreach") statement.
|
||||
A method, constructor, or record-class name stays attached to the open parenthesis (() that follows it.
|
||||
A comma (,) stays attached to the token that precedes it.
|
||||
A line is never broken adjacent to the arrow in a lambda or a switch rule, except that a break may come immediately after the arrow if the text following it consists of a single unbraced expression. Examples:
|
||||
MyLambda<String, Long, Object> lambda =
|
||||
(String label, Long value, Object obj) -> {
|
||||
...
|
||||
};
|
||||
|
||||
Predicate<String> predicate = str ->
|
||||
longExpressionInvolving(str);
|
||||
|
||||
switch (x) {
|
||||
case ColorPoint(Color color, Point(int x, int y)) ->
|
||||
handleColorPoint(color, x, y);
|
||||
...
|
||||
}
|
||||
|
||||
Note: The primary goal for line wrapping is to have clear code, not necessarily code that fits in the smallest number of lines.
|
||||
|
||||
4.5.2 Indent continuation lines at least +4 spaces
|
||||
|
||||
When line-wrapping, each line after the first (each continuation line) is indented at least +4 from the original line.
|
||||
|
||||
When there are multiple continuation lines, indentation may be varied beyond +4 as desired. In general, two continuation lines use the same indentation level if and only if they begin with syntactically parallel elements.
|
||||
|
||||
Section 4.6.3 on Horizontal alignment addresses the discouraged practice of using a variable number of spaces to align certain tokens with previous lines.
|
||||
|
||||
4.6 Whitespace
|
||||
4.6.1 Vertical whitespace (blank lines)
|
||||
|
||||
A single blank line always appears:
|
||||
|
||||
Between consecutive members or initializers of a class: fields, constructors, methods, nested classes, static initializers, and instance initializers.
|
||||
Exception: A blank line between two consecutive fields (having no other code between them) is optional. Such blank lines are used as needed to create logical groupings of fields.
|
||||
Exception: Blank lines between enum constants are covered in Section 4.8.1.
|
||||
As required by other sections of this document (such as Section 3, Source file structure, and Section 3.3, Imports).
|
||||
|
||||
A single blank line may also appear anywhere it improves readability, for example between statements to organize the code into logical subsections. A blank line before the first member or initializer, or after the last member or initializer of the class, is neither encouraged nor discouraged.
|
||||
|
||||
Multiple consecutive blank lines are permitted, but never required (or encouraged).
|
||||
|
||||
4.6.2 Horizontal whitespace
|
||||
|
||||
Beyond where required by the language or other style rules, and apart from within literals, comments and Javadoc, a single ASCII space also appears in the following places only.
|
||||
|
||||
Separating any keyword, such as if, for or catch, from an open parenthesis (() that follows it on that line
|
||||
Separating any keyword, such as else or catch, from a closing curly brace (}) that precedes it on that line
|
||||
Before any open curly brace ({), with two exceptions:
|
||||
@SomeAnnotation({a, b}) (no space is used)
|
||||
String[][] x = {{"foo"}}; (no space is required between {{, by item 10 below)
|
||||
On both sides of any binary or ternary operator. This also applies to the following "operator-like" symbols:
|
||||
the ampersand that separates multiple type bounds: <T extends Foo & Bar>
|
||||
the pipe for a catch block that handles multiple exceptions: catch (FooException | BarException e)
|
||||
the colon (:) in an enhanced for ("foreach") statement
|
||||
the arrow in a lambda expression: (String str) -> str.length()
|
||||
or switch rule: case "FOO" -> bar();
|
||||
but not
|
||||
the two colons (::) of a method reference, which is written like Object::toString
|
||||
the dot separator (.), which is written like object.toString()
|
||||
After ,:; or the closing parenthesis ()) of a cast
|
||||
Between any content and a double slash (//) which begins a comment. Multiple spaces are allowed.
|
||||
Between a double slash (//) which begins a comment and the comment's text. Multiple spaces are allowed.
|
||||
Between the type and identifier of a declaration: List<String> list
|
||||
Optional just inside both braces of an array initializer
|
||||
new int[] {5, 6} and new int[] { 5, 6 } are both valid
|
||||
Between a type annotation and [] or ....
|
||||
|
||||
This rule is never interpreted as requiring or forbidding additional space at the start or end of a line; it addresses only interior space.
|
||||
|
||||
4.6.3 Horizontal alignment: never required
|
||||
|
||||
Terminology Note: Horizontal alignment is the practice of adding a variable number of additional spaces in your code with the goal of making certain tokens appear directly below certain other tokens on previous lines.
|
||||
|
||||
This practice is permitted, but is never required by Google Style. It is not even required to maintain horizontal alignment in places where it was already used.
|
||||
|
||||
Here is an example without alignment, then using alignment:
|
||||
|
||||
private int x; // this is fine
|
||||
private Color color; // this too
|
||||
|
||||
private int x; // permitted, but future edits
|
||||
private Color color; // may leave it unaligned
|
||||
|
||||
Tip: Alignment can aid readability, but attempting to preserve alignment for its own sake creates future problems. For example, consider a change that touches only one line. If that change disrupts the previous alignment, it's important **not** to introduce additional changes on nearby lines simply to realign them. Introducing formatting changes on otherwise unaffected lines corrupts version history, slows down reviewers, and exacerbates merge conflicts. These practical concerns take priority over alignment.
|
||||
|
||||
4.7 Grouping parentheses: recommended
|
||||
|
||||
Optional grouping parentheses are omitted only when author and reviewer agree that there is no reasonable chance the code will be misinterpreted without them, nor would they have made the code easier to read. It is not reasonable to assume that every reader has the entire Java operator precedence table memorized.
|
||||
|
||||
4.8 Specific constructs
|
||||
4.8.1 Enum classes
|
||||
|
||||
After the comma that follows an enum constant, a line break is optional. Additional blank lines (usually just one) are also allowed. This is one possibility:
|
||||
|
||||
private enum Answer {
|
||||
YES {
|
||||
@Override public String toString() {
|
||||
return "yes";
|
||||
}
|
||||
},
|
||||
|
||||
NO,
|
||||
MAYBE
|
||||
}
|
||||
|
||||
An enum class with no methods and no documentation on its constants may optionally be formatted as if it were an array initializer (see Section 4.8.3.1 on array initializers).
|
||||
|
||||
private enum Suit { CLUBS, HEARTS, SPADES, DIAMONDS }
|
||||
|
||||
Since enum classes are classes, all other rules for formatting classes apply.
|
||||
|
||||
4.8.2 Variable declarations
|
||||
4.8.2.1 One variable per declaration
|
||||
|
||||
Every variable declaration (field or local) declares only one variable: declarations such as int a, b; are not used.
|
||||
|
||||
Exception: Multiple variable declarations are acceptable in the header of a for loop.
|
||||
|
||||
4.8.2.2 Declared when needed
|
||||
|
||||
Local variables are not habitually declared at the start of their containing block or block-like construct. Instead, local variables are declared close to the point they are first used (within reason), to minimize their scope. Local variable declarations typically have initializers, or are initialized immediately after declaration.
|
||||
|
||||
4.8.3 Arrays
|
||||
4.8.3.1 Array initializers: can be "block-like"
|
||||
|
||||
Any array initializer may optionally be formatted as if it were a "block-like construct." For example, the following are all valid (not an exhaustive list):
|
||||
|
||||
new int[] { new int[] {
|
||||
0, 1, 2, 3 0,
|
||||
} 1,
|
||||
2,
|
||||
new int[] { 3,
|
||||
0, 1, }
|
||||
2, 3
|
||||
} new int[]
|
||||
{0, 1, 2, 3}
|
||||
4.8.3.2 No C-style array declarations
|
||||
|
||||
The square brackets form a part of the type, not the variable: String[] args, not String args[].
|
||||
|
||||
4.8.4 Switch statements and expressions
|
||||
|
||||
For historical reasons, the Java language has two distinct syntaxes for switch, which we can call old-style and new-style. New-style switches use an arrow (->) after the switch labels, while old-style switches use a colon (:).
|
||||
|
||||
Terminology Note: Inside the braces of a switch block are either one or more switch rules (new-style); or one or more statement groups (old-style). A switch rule consists of a switch label (case ... or default) followed by -> and an expression, block, or throw. A statement group consists of one or more switch labels each followed by a colon, then one or more statements, or, for the last statement group, zero or more statements. (These definitions match the Java Language Specification, §14.11.)
|
||||
|
||||
4.8.4.1 Indentation
|
||||
|
||||
As with any other block, the contents of a switch block are indented +2. Each switch label starts with this +2 indentation.
|
||||
|
||||
In a new-style switch, a switch rule can be written on a single line if it otherwise follows Google style. (It must not exceed the column limit, and if it contains a non-empty block then there must be a line break after {.) The line-wrapping rules of Section 4.5 apply, including the +4 indent for continuation lines. For a switch rule with a non-empty block after the arrow, the same rules apply as for blocks elsewhere: lines between { and } are indented a further +2 relative to the line with the switch label.
|
||||
|
||||
switch (number) {
|
||||
case 0, 1 -> handleZeroOrOne();
|
||||
case 2 ->
|
||||
handleTwoWithAnExtremelyLongMethodCallThatWouldNotFitOnTheSameLine();
|
||||
default -> {
|
||||
logger.atInfo().log("Surprising number %s", number);
|
||||
handleSurprisingNumber(number);
|
||||
}
|
||||
}
|
||||
|
||||
In an old-style switch, the colon of each switch label is followed by a line break. The statements within a statement group are indented a further +2.
|
||||
|
||||
4.8.4.2 Fall-through: commented
|
||||
|
||||
Within an old-style switch block, each statement group either terminates abruptly (with a break, continue, return or thrown exception), or is marked with a comment to indicate that execution will or might continue into the next statement group. Any comment that communicates the idea of fall-through is sufficient (typically // fall through). This special comment is not required in the last statement group of the switch block. Example:
|
||||
|
||||
switch (input) {
|
||||
case 1:
|
||||
case 2:
|
||||
prepareOneOrTwo();
|
||||
// fall through
|
||||
case 3:
|
||||
handleOneTwoOrThree();
|
||||
break;
|
||||
default:
|
||||
handleLargeNumber(input);
|
||||
}
|
||||
|
||||
Notice that no comment is needed after case 1:, only at the end of the statement group.
|
||||
|
||||
There is no fall-through in new-style switches.
|
||||
|
||||
4.8.4.3 Exhaustiveness and presence of the default label
|
||||
|
||||
The Java language requires switch expressions and many kinds of switch statements to be exhaustive. That effectively means that every possible value that could be switched on will be matched by one of the switch labels. A switch is exhaustive if it has a default label, but also for example if the value being switched on is an enum and every value of the enum is matched by a switch label. Google Style requires every switch to be exhaustive, even those where the language itself does not require it. This may require adding a default label, even if it contains no code.
|
||||
|
||||
4.8.4.4 Switch expressions
|
||||
|
||||
Switch expressions must be new-style switches:
|
||||
|
||||
return switch (list.size()) {
|
||||
case 0 -> "";
|
||||
case 1 -> list.getFirst();
|
||||
default -> String.join(", ", list);
|
||||
};
|
||||
4.8.5 Annotations
|
||||
4.8.5.1 Type-use annotations
|
||||
|
||||
Type-use annotations appear immediately before the annotated type. An annotation is a type-use annotation if it is meta-annotated with @Target(ElementType.TYPE_USE). Example:
|
||||
|
||||
final @Nullable String name;
|
||||
|
||||
public @Nullable Person getPersonByName(String name);
|
||||
4.8.5.2 Class, package, and module annotations
|
||||
|
||||
Annotations applying to a class, package, or module declaration appear immediately after the documentation block, and each annotation is listed on a line of its own (that is, one annotation per line). These line breaks do not constitute line-wrapping (Section 4.5, Line-wrapping), so the indentation level is not increased. Examples:
|
||||
|
||||
/** This is a class. */
|
||||
@Deprecated
|
||||
@CheckReturnValue
|
||||
public final class Frozzler { ... }
|
||||
/** This is a package. */
|
||||
@Deprecated
|
||||
@CheckReturnValue
|
||||
package com.example.frozzler;
|
||||
/** This is a module. */
|
||||
@Deprecated
|
||||
@SuppressWarnings("CheckReturnValue")
|
||||
module com.example.frozzler { ... }
|
||||
4.8.5.3 Method and constructor annotations
|
||||
|
||||
The rules for annotations on method and constructor declarations are the same as the previous section. Example:
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public String getNameIfPresent() { ... }
|
||||
|
||||
Exception: A single parameterless annotation may instead appear together with the first line of the signature, for example:
|
||||
|
||||
@Override public int hashCode() { ... }
|
||||
4.8.5.4 Field annotations
|
||||
|
||||
Annotations applying to a field also appear immediately after the documentation block, but in this case, multiple annotations (possibly parameterized) may be listed on the same line; for example:
|
||||
|
||||
@Partial @Mock DataLoader loader;
|
||||
4.8.5.5 Parameter and local variable annotations
|
||||
|
||||
There are no specific rules for formatting annotations on parameters or local variables (except, of course, when the annotation is a type-use annotation).
|
||||
|
||||
4.8.6 Comments
|
||||
|
||||
This section addresses implementation comments. Javadoc is addressed separately in Section 7, Javadoc.
|
||||
|
||||
Any line break may be preceded by arbitrary whitespace followed by an implementation comment. Such a comment renders the line non-blank.
|
||||
|
||||
4.8.6.1 Block comment style
|
||||
|
||||
Block comments are indented at the same level as the surrounding code. They may be in /* ... */ style or // ... style. For multi-line /* ... */ comments, subsequent lines must start with * aligned with the * on the previous line.
|
||||
|
||||
/*
|
||||
* This is // And so /* Or you can
|
||||
* okay. // is this. * even do this. */
|
||||
*/
|
||||
|
||||
Comments are not enclosed in boxes drawn with asterisks or other characters.
|
||||
|
||||
Tip: When writing multi-line comments, use the /* ... */ style if you want automatic code formatters to re-wrap the lines when necessary (paragraph-style). Most formatters don't re-wrap lines in // ... style comment blocks.
|
||||
|
||||
4.8.6.2 TODO comments
|
||||
|
||||
Use TODO comments for code that is temporary, a short-term solution, or good-enough but not perfect.
|
||||
|
||||
A TODO comment begins with the word TODO in all caps, a following colon, and a link to a resource that contains the context, ideally a bug reference. A bug reference is preferable because bugs are tracked and have follow-up comments. Follow this piece of context with an explanatory string introduced with a hyphen -.
|
||||
|
||||
The purpose is to have a consistent TODO format that can be searched to find out how to get more details.
|
||||
|
||||
// TODO: crbug.com/12345678 - Remove this after the 2047q4 compatibility window expires.
|
||||
|
||||
|
||||
Avoid adding TODOs that refer to an individual or team as the context:
|
||||
|
||||
// TODO: @yourusername - File an issue and use a '*' for repetition.
|
||||
|
||||
|
||||
If your TODO is of the form "At a future date do something" make sure that you either include a very specific date ("Fix by November 2005") or a very specific event ("Remove this code when all clients can handle XML responses.").
|
||||
|
||||
4.8.7 Modifiers
|
||||
|
||||
Class and member modifiers, when present, appear in the order recommended by the Java Language Specification:
|
||||
|
||||
public protected private abstract default static final sealed non-sealed
|
||||
transient volatile synchronized native strictfp
|
||||
|
||||
|
||||
Modifiers on requires module directives, when present, appear in the following order:
|
||||
|
||||
transitive static
|
||||
4.8.8 Numeric Literals
|
||||
|
||||
long-valued integer literals use an uppercase L suffix, never lowercase (to avoid confusion with the digit 1). For example, 3000000000L rather than 3000000000l.
|
||||
|
||||
4.8.9 Text Blocks
|
||||
|
||||
The opening """ of a text block is always on a new line. That line may either follow the same indentation rules as other constructs, or it may have no indentation at all (so it starts at the left margin). The closing """ is on a new line with the same indentation as the opening """, and may be followed on the same line by further code. Each line of text in the text block is indented at least as much as the opening and closing """. (If a line is indented further, then the string literal defined by the text block will have space at the start of that line.)
|
||||
|
||||
The contents of a text block may exceed the column limit.
|
||||
|
||||
5 Naming
|
||||
5.1 Rules common to all identifiers
|
||||
|
||||
Identifiers use only ASCII letters and digits, and, in a small number of cases noted below, underscores. Thus each valid identifier name is matched by the regular expression \w+ .
|
||||
|
||||
In Google Style, special prefixes or suffixes are not used. For example, these names are not Google Style: name_, mName, s_name and kName.
|
||||
|
||||
5.2 Rules by identifier type
|
||||
5.2.1 Package and module names
|
||||
|
||||
Package and module names use only lowercase letters and digits (no underscores). Consecutive words are simply concatenated together. For example, com.example.deepspace, not com.example.deepSpace or com.example.deep_space.
|
||||
|
||||
5.2.2 Class names
|
||||
|
||||
Class names are written in UpperCamelCase.
|
||||
|
||||
Class names are typically nouns or noun phrases. For example, Character or ImmutableList. Interface names may also be nouns or noun phrases (for example, List), but may sometimes be adjectives or adjective phrases instead (for example, Readable).
|
||||
|
||||
There are no specific rules or even well-established conventions for naming annotation types.
|
||||
|
||||
A test class has a name that ends with Test, for example, HashIntegrationTest. If it covers a single class, its name is the name of that class plus Test, for example HashImplTest.
|
||||
|
||||
5.2.3 Method names
|
||||
|
||||
Method names are written in lowerCamelCase.
|
||||
|
||||
Method names are typically verbs or verb phrases. For example, sendMessage or stop.
|
||||
|
||||
Underscores may appear in JUnit test method names to separate logical components of the name, with each component written in lowerCamelCase, for example transferMoney_deductsFromSource. There is no One Correct Way to name test methods.
|
||||
|
||||
5.2.4 Constant names
|
||||
|
||||
Constant names use UPPER_SNAKE_CASE: all uppercase letters, with each word separated from the next by a single underscore. But what is a constant, exactly?
|
||||
|
||||
Constants are static final fields whose contents are deeply immutable and whose methods have no detectable side effects. Examples include primitives, strings, immutable value classes, and anything set to null. If any of the instance's observable state can change, it is not a constant. Merely intending to never mutate the object is not enough. Examples:
|
||||
|
||||
// Constants
|
||||
static final int NUMBER = 5;
|
||||
static final ImmutableList<String> NAMES = ImmutableList.of("Ed", "Ann");
|
||||
static final Map<String, Integer> AGES = ImmutableMap.of("Ed", 35, "Ann", 32);
|
||||
static final Joiner COMMA_JOINER = Joiner.on(','); // because Joiner is immutable
|
||||
static final SomeMutableType[] EMPTY_ARRAY = {};
|
||||
|
||||
// Not constants
|
||||
static String nonFinal = "non-final";
|
||||
final String nonStatic = "non-static";
|
||||
static final Set<String> mutableCollection = new HashSet<String>();
|
||||
static final ImmutableSet<SomeMutableType> mutableElements = ImmutableSet.of(mutable);
|
||||
static final ImmutableMap<String, SomeMutableType> mutableValues =
|
||||
ImmutableMap.of("Ed", mutableInstance, "Ann", mutableInstance2);
|
||||
static final Logger logger = Logger.getLogger(MyClass.getName());
|
||||
static final String[] nonEmptyArray = {"these", "can", "change"};
|
||||
|
||||
These names are typically nouns or noun phrases.
|
||||
|
||||
5.2.5 Non-constant field names
|
||||
|
||||
Non-constant field names (static or otherwise) are written in lowerCamelCase.
|
||||
|
||||
These names are typically nouns or noun phrases. For example, computedValues or index.
|
||||
|
||||
5.2.6 Parameter names
|
||||
|
||||
Parameter names are written in lowerCamelCase.
|
||||
|
||||
One-character parameter names in public methods should be avoided.
|
||||
|
||||
5.2.7 Local variable names
|
||||
|
||||
Local variable names are written in lowerCamelCase.
|
||||
|
||||
Even when final and immutable, local variables are not considered to be constants, and should not be styled as constants.
|
||||
|
||||
5.2.8 Type variable names
|
||||
|
||||
Each type variable is named in one of two styles:
|
||||
|
||||
A single capital letter, optionally followed by a single numeral (such as E, T, X, T2)
|
||||
A name in the form used for classes (see Section 5.2.2, Class names), followed by the capital letter T (examples: RequestT, FooBarT).
|
||||
5.3 Camel case: defined
|
||||
|
||||
Sometimes there is more than one reasonable way to convert an English phrase into camel case, such as when acronyms or unusual constructs like "IPv6" or "iOS" are present. To improve predictability, Google Style specifies the following (nearly) deterministic scheme.
|
||||
|
||||
Beginning with the prose form of the name:
|
||||
|
||||
Convert the phrase to plain ASCII and remove any apostrophes. For example, "Müller's algorithm" might become "Muellers algorithm".
|
||||
Divide this result into words, splitting on spaces and any remaining punctuation (typically hyphens).
|
||||
Recommended: if any word already has a conventional camel-case appearance in common usage, split this into its constituent parts (e.g., "AdWords" becomes "ad words"). Note that a word such as "iOS" is not really in camel case per se; it defies any convention, so this recommendation does not apply.
|
||||
Now lowercase everything (including acronyms), then uppercase only the first character of:
|
||||
... each word, to yield upper camel case, or
|
||||
... each word except the first, to yield lower camel case
|
||||
Finally, join all the words into a single identifier. Note that the casing of the original words is almost entirely disregarded.
|
||||
|
||||
In very rare circumstances (for example, multipart version numbers), you may need to use underscores to separate adjacent numbers, since numbers do not have upper and lower case variants.
|
||||
|
||||
Examples:
|
||||
|
||||
Prose form Correct Incorrect
|
||||
"XML HTTP request" XmlHttpRequest XMLHTTPRequest
|
||||
"new customer ID" newCustomerId newCustomerID
|
||||
"inner stopwatch" innerStopwatch innerStopWatch
|
||||
"supports IPv6 on iOS?" supportsIpv6OnIos supportsIPv6OnIOS
|
||||
"YouTube importer" YouTubeImporter
|
||||
YoutubeImporter*
|
||||
"Turn on 2SV" turnOn2sv turnOn2Sv
|
||||
"Guava 33.4.6" guava33_4_6 guava3346
|
||||
|
||||
*Acceptable, but not recommended.
|
||||
|
||||
Note: Some words are ambiguously hyphenated in the English language: for example "nonempty" and "non-empty" are both correct, so the method names checkNonempty and checkNonEmpty are likewise both correct.
|
||||
|
||||
6 Programming Practices
|
||||
6.1 @Override: always used
|
||||
|
||||
A method is marked with the @Override annotation whenever it is legal. This includes a class method overriding a superclass method, a class method implementing an interface method, an interface method respecifying a superinterface method, and an explicitly declared accessor method for a record component.
|
||||
|
||||
Exception: @Override may be omitted when the parent method is @Deprecated.
|
||||
|
||||
6.2 Caught exceptions: not ignored
|
||||
|
||||
It is very rarely correct to do nothing in response to a caught exception. (Typical responses are to log it, or if it is considered "impossible", rethrow it as an AssertionError.)
|
||||
|
||||
When it truly is appropriate to take no action whatsoever in a catch block, the reason this is justified is explained in a comment.
|
||||
|
||||
try {
|
||||
int i = Integer.parseInt(response);
|
||||
return handleNumericResponse(i);
|
||||
} catch (NumberFormatException ok) {
|
||||
// it's not numeric; that's fine, just continue
|
||||
}
|
||||
return handleTextResponse(response);
|
||||
6.3 Static members: qualified using class
|
||||
|
||||
When a reference to a static class member must be qualified, it is qualified with that class's name, not with a reference or expression of that class's type.
|
||||
|
||||
Foo aFoo = ...;
|
||||
Foo.aStaticMethod(); // good
|
||||
aFoo.aStaticMethod(); // bad
|
||||
somethingThatYieldsAFoo().aStaticMethod(); // very bad
|
||||
6.4 Finalizers: not used
|
||||
|
||||
Do not override Object.finalize. Finalization support is scheduled for removal.
|
||||
|
||||
7 Javadoc
|
||||
7.1 Formatting
|
||||
7.1.1 General form
|
||||
|
||||
The basic formatting of Javadoc blocks is as seen in this example:
|
||||
|
||||
/**
|
||||
* Multiple lines of Javadoc text are written here,
|
||||
* wrapped normally...
|
||||
*/
|
||||
public int method(String p1) { ... }
|
||||
|
||||
... or in this single-line example:
|
||||
|
||||
/** An especially short bit of Javadoc. */
|
||||
|
||||
The basic form is always acceptable. The single-line form may be substituted when the entirety of the Javadoc block (including comment markers) can fit on a single line. Note that this only applies when there are no block tags such as @param.
|
||||
|
||||
7.1.2 Paragraphs
|
||||
|
||||
One blank line—that is, a line containing only the aligned leading asterisk (*)—appears between paragraphs, and before the group of block tags if present. Each paragraph except the first has <p> immediately before the first word, with no space after it. HTML tags for other block-level elements, such as <ul> or <table>, are not preceded with <p>.
|
||||
|
||||
7.1.3 Block tags
|
||||
|
||||
Any of the standard "block tags" that are used appear in the order @param, @return, @throws, @deprecated, and these four types never appear with an empty description. When a block tag doesn't fit on a single line, continuation lines are indented four (or more) spaces from the position of the @.
|
||||
|
||||
7.2 The summary fragment
|
||||
|
||||
Each Javadoc block begins with a brief summary fragment. This fragment is very important: it is the only part of the text that appears in certain contexts such as class and method indexes.
|
||||
|
||||
This is a fragment—a noun phrase or verb phrase, not a complete sentence. It does not begin with A {@code Foo} is a..., or This method returns..., nor does it form a complete imperative sentence like Save the record.. However, the fragment is capitalized and punctuated as if it were a complete sentence.
|
||||
|
||||
Tip: A common mistake is to write simple Javadoc in the form /** @return the customer ID */. This is incorrect, and should be changed to /** Returns the customer ID. */ or /** {@return the customer ID} */.
|
||||
|
||||
7.3 Where Javadoc is used
|
||||
|
||||
At the minimum, Javadoc is present for every visible class, member, or record component, with a few exceptions noted below. A top-level class is visible if it is public; a member is visible if it is public or protected and its containing class is visible; and a record component is visible if its containing record is visible.
|
||||
|
||||
Additional Javadoc content may also be present, as explained in Section 7.3.4, Non-required Javadoc.
|
||||
|
||||
7.3.1 Exception: self-explanatory members
|
||||
|
||||
Javadoc is optional for "simple, obvious" members and record components, such as a getFoo() method, if there really and truly is nothing else worthwhile to say but "the foo".
|
||||
|
||||
Important: it is not appropriate to cite this exception to justify omitting relevant information that a typical reader might need to know. For example, for a record component named canonicalName, don't omit its documentation (with the rationale that it would say only @param canonicalName the canonical name) if a typical reader may have no idea what the term "canonical name" means!
|
||||
|
||||
7.3.2 Exception: overrides
|
||||
|
||||
Javadoc is not always present on a method that overrides a supertype method.
|
||||
|
||||
7.3.4 Non-required Javadoc
|
||||
|
||||
Other classes, members, and record components have Javadoc as needed or desired.
|
||||
|
||||
Whenever an implementation comment would be used to define the overall purpose or behavior of a class or member, that comment is written as Javadoc instead (using /**).
|
||||
|
||||
Non-required Javadoc is not strictly required to follow the formatting rules of Sections 7.1.1, 7.1.2, 7.1.3, and 7.2, though it is of course recommended.
|
||||
16
ai/skills/javascript_expert/SKILL.md
Normal file
16
ai/skills/javascript_expert/SKILL.md
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
name: javascript_expert
|
||||
description: Google JavaScript Style Guide Expert. Covers modern JS (ES6+) and Closure-style conventions.
|
||||
---
|
||||
# JavaScript Expert
|
||||
|
||||
Expert in Google JavaScript Style Guide.
|
||||
|
||||
## Core Mandate
|
||||
Strictly follow [STYLE_GUIDE.md](./STYLE_GUIDE.md).
|
||||
|
||||
## Key Principles
|
||||
- Use const and let.
|
||||
- Arrow functions preferred for callbacks.
|
||||
- Minimal global state.
|
||||
- Proper use of modules and exports.
|
||||
2660
ai/skills/javascript_expert/STYLE_GUIDE.md
Normal file
2660
ai/skills/javascript_expert/STYLE_GUIDE.md
Normal file
File diff suppressed because it is too large
Load Diff
15
ai/skills/json_expert/SKILL.md
Normal file
15
ai/skills/json_expert/SKILL.md
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
name: json_expert
|
||||
description: Google JSON Style Guide Expert. For consistent data exchange formats.
|
||||
---
|
||||
# JSON Expert
|
||||
|
||||
Expert in Google JSON Style Guide.
|
||||
|
||||
## Core Mandate
|
||||
Strictly follow [STYLE_GUIDE.md](./STYLE_GUIDE.md).
|
||||
|
||||
## Key Principles
|
||||
- Clear property naming.
|
||||
- Consistent structure for lists and maps.
|
||||
- Avoid redundant data.
|
||||
400
ai/skills/json_expert/STYLE_GUIDE.md
Normal file
400
ai/skills/json_expert/STYLE_GUIDE.md
Normal file
@@ -0,0 +1,400 @@
|
||||
Google JSON Style Guide
|
||||
|
||||
Revision 0.9
|
||||
|
||||
Each style point has a summary for which additional information is available by toggling the accompanying arrow button that looks this way: ▶. You may toggle all summaries with the big arrow button:
|
||||
|
||||
▶ Toggle all summaries
|
||||
Table of Contents
|
||||
General Guidelines
|
||||
|
||||
Comments Double Quotes Flattened data vs Structured Hierarchy
|
||||
|
||||
|
||||
Property Name Guidelines
|
||||
|
||||
Property Name Format Key Names in JSON Maps Reserved Property Names Singular vs Plural Property Names Naming Conflicts
|
||||
|
||||
|
||||
Property Value Guidelines
|
||||
|
||||
Property Value Format Empty/Null Property Values Enum Values
|
||||
|
||||
|
||||
Property Value Data Types
|
||||
|
||||
Date Property Values Time Duration Property Values Latitude/Longitude Property Values
|
||||
|
||||
|
||||
JSON Structure & Reserved Property Names
|
||||
|
||||
|
||||
|
||||
Top-Level Reserved Property Names
|
||||
|
||||
apiVersion context id method params data error
|
||||
|
||||
|
||||
Reserved Property Names in the data object
|
||||
|
||||
data.kind data.fields data.etag data.id data.lang data.updated data.deleted data.items
|
||||
|
||||
|
||||
Reserved Property Names for Paging
|
||||
|
||||
data.currentItemCount data.itemsPerPage data.startIndex data.totalItems data.pagingLinkTemplate data.pageIndex data.totalPages
|
||||
|
||||
|
||||
Reserved Property Names for Links
|
||||
|
||||
data.self / data.selfLink data.edit / data.editLink data.next / data.nextLink data.previous / data.previousLink
|
||||
|
||||
|
||||
Reserved Property Names in the error object
|
||||
|
||||
error.code error.message error.errors error.errors[].domain error.errors[].reason error.errors[].message error.errors[].location error.errors[].locationType error.errors[].extendedHelp error.errors[].sendReport
|
||||
|
||||
|
||||
Property Ordering
|
||||
|
||||
Kind Property Items Property Property Ordering Example
|
||||
|
||||
|
||||
Examples
|
||||
|
||||
YouTube JSON API Paging Example
|
||||
|
||||
|
||||
Appendix
|
||||
|
||||
Appendix A: Reserved JavaScript Words
|
||||
Important Note
|
||||
Display Hidden Details in this Guide
|
||||
▶
|
||||
This style guide contains many details that are initially hidden from view. They are marked by the triangle icon, which you see here on your left. Click it now. You should see "Hooray" appear below.
|
||||
Introduction
|
||||
|
||||
This style guide documents guidelines and recommendations for building JSON APIs at Google. In general, JSON APIs should follow the spec found at JSON.org. This style guide clarifies and standardizes specific cases so that JSON APIs from Google have a standard look and feel. These guidelines are applicable to JSON requests and responses in both RPC-based and REST-based APIs.
|
||||
|
||||
Definitions
|
||||
|
||||
For the purposes of this style guide, we define the following terms:
|
||||
|
||||
property - a name/value pair inside a JSON object.
|
||||
property name - the name (or key) portion of the property.
|
||||
property value - the value portion of the property.
|
||||
{
|
||||
// The name/value pair together is a "property".
|
||||
"propertyName": "propertyValue"
|
||||
}
|
||||
|
||||
|
||||
Javascript's number type encompasses all floating-point numbers, which is a broad designation. In this guide, number will refer to JavaScript's number type, while integer will refer to integers.
|
||||
|
||||
General Guidelines
|
||||
Comments
|
||||
▶
|
||||
No comments in JSON objects.
|
||||
Double Quotes
|
||||
▶
|
||||
Use double quotes.
|
||||
Flattened data vs Structured Hierarchy
|
||||
▶
|
||||
Data should not be arbitrarily grouped for convenience.
|
||||
Property Name Guidelines
|
||||
Property Name Format
|
||||
▶
|
||||
Choose meaningful property names.
|
||||
Key Names in JSON Maps
|
||||
▶
|
||||
JSON maps can use any Unicode character in key names.
|
||||
Reserved Property Names
|
||||
▶
|
||||
Certain property names are reserved for consistent use across services.
|
||||
Singular vs Plural Property Names
|
||||
▶
|
||||
Array types should have plural property names. All other property names should be singular.
|
||||
Naming Conflicts
|
||||
▶
|
||||
Avoid naming conflicts by choosing a new property name or versioning the API.
|
||||
Property Value Guidelines
|
||||
Property Value Format
|
||||
▶
|
||||
Property values must be booleans, numbers, Unicode strings, objects, arrays, or null.
|
||||
Empty/Null Property Values
|
||||
▶
|
||||
Consider removing empty or null values.
|
||||
Enum Values
|
||||
▶
|
||||
Enum values should be represented as strings.
|
||||
Property Value Data Types
|
||||
|
||||
As mentioned above, property value types must be booleans, numbers, strings, objects, arrays, or null. However, it is useful define a set of standard data types when dealing with certain values. These data types will always be strings, but they will be formatted in a specific manner so that they can be easily parsed.
|
||||
|
||||
Date Property Values
|
||||
▶
|
||||
Dates should be formatted as recommended by RFC 3339.
|
||||
Time Duration Property Values
|
||||
▶
|
||||
Time durations should be formatted as recommended by ISO 8601.
|
||||
Latitude/Longitude Property Values
|
||||
▶
|
||||
Latitudes/Longitudes should be formatted as recommended by ISO 6709.
|
||||
JSON Structure & Reserved Property Names
|
||||
|
||||
In order to maintain a consistent interface across APIs, JSON objects should follow the structure outlined below. This structure applies to both requests and responses made with JSON. Within this structure, there are certain property names that are reserved for specific uses. These properties are NOT required; in other words, each reserved property may appear zero or one times. But if a service needs these properties, this naming convention is recommended. Here is a schema of the JSON structure, represented in Orderly format (which in turn can be compiled into a JSONSchema). You can few examples of the JSON structure at the end of this guide.
|
||||
|
||||
object {
|
||||
string apiVersion?;
|
||||
string context?;
|
||||
string id?;
|
||||
string method?;
|
||||
object {
|
||||
string id?
|
||||
}* params?;
|
||||
object {
|
||||
string kind?;
|
||||
string fields?;
|
||||
string etag?;
|
||||
string id?;
|
||||
string lang?;
|
||||
string updated?; # date formatted RFC 3339
|
||||
boolean deleted?;
|
||||
integer currentItemCount?;
|
||||
integer itemsPerPage?;
|
||||
integer startIndex?;
|
||||
integer totalItems?;
|
||||
integer pageIndex?;
|
||||
integer totalPages?;
|
||||
string pageLinkTemplate /^https?:/ ?;
|
||||
object {}* next?;
|
||||
string nextLink?;
|
||||
object {}* previous?;
|
||||
string previousLink?;
|
||||
object {}* self?;
|
||||
string selfLink?;
|
||||
object {}* edit?;
|
||||
string editLink?;
|
||||
array [
|
||||
object {}*;
|
||||
] items?;
|
||||
}* data?;
|
||||
object {
|
||||
integer code?;
|
||||
string message?;
|
||||
array [
|
||||
object {
|
||||
string domain?;
|
||||
string reason?;
|
||||
string message?;
|
||||
string location?;
|
||||
string locationType?;
|
||||
string extendedHelp?;
|
||||
string sendReport?;
|
||||
}*;
|
||||
] errors?;
|
||||
}* error?;
|
||||
}*;
|
||||
|
||||
|
||||
The JSON object has a few top-level properties, followed by either a data object or an error object, but not both. An explanation of each of these properties can be found below.
|
||||
|
||||
Top-Level Reserved Property Names
|
||||
|
||||
The top-level of the JSON object may contain the following properties.
|
||||
|
||||
apiVersion
|
||||
▶
|
||||
Property Value Type: string
|
||||
Parent: -
|
||||
context
|
||||
▶
|
||||
Property Value Type: string
|
||||
Parent: -
|
||||
id
|
||||
▶
|
||||
Property Value Type: string
|
||||
Parent: -
|
||||
method
|
||||
▶
|
||||
Property Value Type: string
|
||||
Parent: -
|
||||
params
|
||||
▶
|
||||
Property Value Type: object
|
||||
Parent: -
|
||||
data
|
||||
▶
|
||||
Property Value Type: object
|
||||
Parent: -
|
||||
error
|
||||
▶
|
||||
Property Value Type: object
|
||||
Parent: -
|
||||
Reserved Property Names in the data object
|
||||
|
||||
The data property of the JSON object may contain the following properties.
|
||||
|
||||
data.kind
|
||||
▶
|
||||
Property Value Type: string
|
||||
Parent: data
|
||||
data.fields
|
||||
▶
|
||||
Property Value Type: string
|
||||
Parent: data
|
||||
data.etag
|
||||
▶
|
||||
Property Value Type: string
|
||||
Parent: data
|
||||
data.id
|
||||
▶
|
||||
Property Value Type: string
|
||||
Parent: data
|
||||
data.lang
|
||||
▶
|
||||
Property Value Type: string (formatted as specified in BCP 47)
|
||||
Parent: data (or any child element)
|
||||
data.updated
|
||||
▶
|
||||
Property Value Type: string (formatted as specified in RFC 3339)
|
||||
Parent: data
|
||||
data.deleted
|
||||
▶
|
||||
Property Value Type: boolean
|
||||
Parent: data (or any child element)
|
||||
data.items
|
||||
▶
|
||||
Property Value Type: array
|
||||
Parent: data
|
||||
Reserved Property Names for Paging
|
||||
|
||||
The following properties are located in the data object, and help page through a list of items. Some of the language and concepts are borrowed from the OpenSearch specification.
|
||||
|
||||
The paging properties below allow for various styles of paging, including:
|
||||
|
||||
Previous/Next paging - Allows user's to move forward and backward through a list, one page at a time. The nextLink and previousLink properties (described in the "Reserved Property Names for Links" section below) are used for this style of paging.
|
||||
Index-based paging - Allows user's to jump directly to a specific item position within a list of items. For example, to load 10 items starting at item 200, the developer may point the user to a url with the query string ?startIndex=200.
|
||||
Page-based paging - Allows user's to jump directly to a specific page within the items. This is similar to index-based paging, but saves the developer the extra step of having to calculate the item index for a new page of items. For example, rather than jump to item number 200, the developer could jump to page 20. The urls during page-based paging could use the query string ?page=1 or ?page=20. The pageIndex and totalPages properties are used for this style of paging.
|
||||
|
||||
An example of how to use these properties to implement paging can be found at the end of this guide.
|
||||
|
||||
data.currentItemCount
|
||||
▶
|
||||
Property Value Type: integer
|
||||
Parent: data
|
||||
data.itemsPerPage
|
||||
▶
|
||||
Property Value Type: integer
|
||||
Parent: data
|
||||
data.startIndex
|
||||
▶
|
||||
Property Value Type: integer
|
||||
Parent: data
|
||||
data.totalItems
|
||||
▶
|
||||
Property Value Type: integer
|
||||
Parent: data
|
||||
data.pagingLinkTemplate
|
||||
▶
|
||||
Property Value Type: string
|
||||
Parent: data
|
||||
data.pageIndex
|
||||
▶
|
||||
Property Value Type: integer
|
||||
Parent: data
|
||||
data.totalPages
|
||||
▶
|
||||
Property Value Type: integer
|
||||
Parent: data
|
||||
Reserved Property Names for Links
|
||||
|
||||
The following properties are located in the data object, and represent references to other resources. There are two forms of link properties: 1) objects, which can contain any sort of reference (such as a JSON-RPC object), and 2) URI strings, which represent URIs to resources (and will always be suffixed with "Link").
|
||||
|
||||
data.self / data.selfLink
|
||||
▶
|
||||
Property Value Type: object / string
|
||||
Parent: data
|
||||
data.edit / data.editLink
|
||||
▶
|
||||
Property Value Type: object / string
|
||||
Parent: data
|
||||
data.next / data.nextLink
|
||||
▶
|
||||
Property Value Type: object / string
|
||||
Parent: data
|
||||
data.previous / data.previousLink
|
||||
▶
|
||||
Property Value Type: object / string
|
||||
Parent: data
|
||||
Reserved Property Names in the error object
|
||||
|
||||
The error property of the JSON object may contain the following properties.
|
||||
|
||||
error.code
|
||||
▶
|
||||
Property Value Type: integer
|
||||
Parent: error
|
||||
error.message
|
||||
▶
|
||||
Property Value Type: string
|
||||
Parent: error
|
||||
error.errors
|
||||
▶
|
||||
Property Value Type: array
|
||||
Parent: error
|
||||
error.errors[].domain
|
||||
▶
|
||||
Property Value Type: string
|
||||
Parent: error.errors
|
||||
error.errors[].reason
|
||||
▶
|
||||
Property Value Type: string
|
||||
Parent: error.errors
|
||||
error.errors[].message
|
||||
▶
|
||||
Property Value Type: string
|
||||
Parent: error.errors
|
||||
error.errors[].location
|
||||
▶
|
||||
Property Value Type: string
|
||||
Parent: error.errors
|
||||
error.errors[].locationType
|
||||
▶
|
||||
Property Value Type: string
|
||||
Parent: error.errors
|
||||
error.errors[].extendedHelp
|
||||
▶
|
||||
Property Value Type: string
|
||||
Parent: error.errors
|
||||
error.errors[].sendReport
|
||||
▶
|
||||
Property Value Type: string
|
||||
Parent: error.errors
|
||||
Property Ordering
|
||||
|
||||
Properties can be in any order within the JSON object. However, in some cases the ordering of properties can help parsers quickly interpret data and lead to better performance. One example is a pull parser in a mobile environment, where performance and memory are critical, and unnecessary parsing should be avoided.
|
||||
|
||||
Kind Property
|
||||
▶
|
||||
kind should be the first property
|
||||
Items Property
|
||||
▶
|
||||
items should be the last property in the data object
|
||||
Property Ordering Example
|
||||
▶
|
||||
Examples
|
||||
YouTube JSON API
|
||||
▶
|
||||
Here's an example of the YouTube JSON API's response object. You can learn more about YouTube's JSON API here: https://code.google.com/apis/youtube/2.0/developers_guide_jsonc.html.
|
||||
Paging Example
|
||||
▶
|
||||
This example demonstrates how the Google search items could be represented as a JSON object, with special attention to the paging variables.
|
||||
Appendix
|
||||
Appendix A: Reserved JavaScript Words
|
||||
▶
|
||||
A list of reserved JavaScript words that should be avoided in property names.
|
||||
|
||||
Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 3.0 License, and code samples are licensed under the Apache 2.0 License.
|
||||
|
||||
Revision 0.9
|
||||
15
ai/skills/lisp_expert/SKILL.md
Normal file
15
ai/skills/lisp_expert/SKILL.md
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
name: lisp_expert
|
||||
description: Google Common Lisp Style Guide Expert. Use this to ensure all Lisp code and plans follow Google's official style guide.
|
||||
---
|
||||
# Lisp Expert
|
||||
|
||||
Expert in Google Common Lisp Style Guide.
|
||||
|
||||
## Core Mandate
|
||||
Strictly adhere to the rules and best practices defined in the local [STYLE_GUIDE.md](./STYLE_GUIDE.md).
|
||||
|
||||
## Key Guidelines
|
||||
- Focus on clarity and consistency in S-expressions.
|
||||
- Use macros judiciously as per the guide.
|
||||
- Follow naming conventions and formatting rules precisely.
|
||||
314
ai/skills/lisp_expert/STYLE_GUIDE.md
Normal file
314
ai/skills/lisp_expert/STYLE_GUIDE.md
Normal file
@@ -0,0 +1,314 @@
|
||||
Google Common Lisp Style Guide
|
||||
|
||||
Revision 1.28
|
||||
|
||||
Robert Brown
|
||||
François-René Rideau
|
||||
In memoriam Dan Weinreb
|
||||
|
||||
Patterns mean "I have run out of language." — Rich Hickey
|
||||
|
||||
Each style point has a summary for which additional information is available by toggling the accompanying arrow button that looks this way: ▶. You may toggle all summaries with the big arrow button:
|
||||
|
||||
▶ Toggle all summaries
|
||||
Table of Contents
|
||||
Meta-Guide
|
||||
|
||||
Must, Should, May, or Not Permission and Forgiveness Conventions Old Code Future Topics
|
||||
|
||||
|
||||
General Guidelines
|
||||
|
||||
Principles Priorities Architecture Using Libraries Open-Sourcing Code Development Process
|
||||
|
||||
|
||||
Formatting
|
||||
|
||||
Spelling and Abbreviations Line length Indentation File Header Vertical white space Horizontal white space
|
||||
|
||||
|
||||
Documentation
|
||||
|
||||
Document everything Comment semicolons Grammar and punctuation Attention Required Domain-Specific Languages
|
||||
|
||||
|
||||
Naming
|
||||
|
||||
Symbol guidelines Denote intent, not content Global variables and constants Predicate names Omit library prefixes Packages
|
||||
|
||||
|
||||
Language usage guidelines
|
||||
|
||||
Mostly Functional Style Recursion Special variables Assignment Assertions and Conditions Type Checking CLOS
|
||||
|
||||
|
||||
Meta-language guidelines
|
||||
|
||||
Macros EVAL-WHEN Read-time evaluation EVAL INTERN and UNINTERN
|
||||
|
||||
|
||||
Data Representation
|
||||
|
||||
NIL: empty-list, false and I Don't Know Do not abuse lists Lists vs. structures vs. multiple values Lists vs. Pairs Lists vs. Arrays Lists vs. Sets
|
||||
|
||||
|
||||
Proper Forms
|
||||
|
||||
Defining Constants Defining Functions Conditional Expressions Identity, Equality and Comparisons Iteration I/O
|
||||
|
||||
|
||||
Optimization
|
||||
|
||||
Avoid Allocation Unsafe Operations DYNAMIC-EXTENT REDUCE vs APPLY Avoid NCONC
|
||||
|
||||
|
||||
Pitfalls
|
||||
|
||||
#'FUN vs. 'FUN Pathnames SATISFIES
|
||||
Important Note
|
||||
Note: Displaying Hidden Details in this Guide
|
||||
▶
|
||||
This style guide contains many details that are initially hidden from view. They are marked by the triangle icon, which you see here on your left. Click it now. You should see "Hooray" appear below.
|
||||
Background
|
||||
|
||||
Common Lisp is a powerful multiparadigm programming language. With great power comes great responsibility.
|
||||
|
||||
This guide recommends formatting and stylistic choices designed to make your code easier for other people to understand. For those internal applications and free software libraries that we develop at Google, you should keep within these guidelines when making changes. Note however that each project has its own rules and customs that complement or override these general guidelines; the speed-oriented QPX low fare search engine notably has a very different style and feel from the QRes reservation system.
|
||||
|
||||
If you're writing Common Lisp code outside Google, we invite you to consider these guidelines. You may find some of them useful where they don't conflict with other priorities you have. We welcome remarks and constructive feedback on how to improve our guide, and on what alternate styles work for you and why.
|
||||
|
||||
This guide is not a Common Lisp tutorial. For basic information about the language, please consult Practical Common Lisp. For a language reference, please consult the Common Lisp HyperSpec. For more detailed style guidance, take (with a pinch of salt) a look at Peter Norvig and Kent Pitman's style guide.
|
||||
|
||||
Meta-Guide
|
||||
Must, Should, May, or Not
|
||||
▶
|
||||
Each guideline's level of importance is indicated by use of the following keywords and phrases, adapted from RFC 2119.
|
||||
Permission and Forgiveness
|
||||
▶
|
||||
There are cases where transgression of some of these rules is useful or even necessary. In some cases, you must seek permission or obtain forgiveness from the proper people.
|
||||
Conventions
|
||||
▶
|
||||
You MUST follow conventions. They are not optional.
|
||||
Old Code
|
||||
▶
|
||||
Fix old code as you go.
|
||||
Future Topics
|
||||
▶
|
||||
There are many topics for additional standardization not covered by current version of this document, but deferred to future versions.
|
||||
General Guidelines
|
||||
Principles
|
||||
▶
|
||||
There are some basic principles for team software development that every developer must keep in mind. Whenever the detailed guidelines are inadequate, confusing or contradictory, refer back to these principles for guidance:
|
||||
Every developer's code must be easy for another developer to read, understand, and modify — even if the first developer isn't around to explain it. (This is the "hit by a truck" principle.)
|
||||
Everybody's code should look the same. Ideally, there should be no way to look at lines of code and recognize it as "Fred's code" by its style.
|
||||
Be precise.
|
||||
Be concise.
|
||||
KISS — Keep It Simple, Stupid.
|
||||
Use the smallest hammer for the job.
|
||||
Use common sense.
|
||||
Keep related code together. Minimize the amount of jumping around someone has to do to understand an area of code.
|
||||
Priorities
|
||||
▶
|
||||
|
||||
When making decisions about how to write a given piece of code, aim for the following -ilities in this priority order:
|
||||
|
||||
Usability by the customer
|
||||
Debuggability/Testability
|
||||
Readability/Comprehensibility
|
||||
Extensibility/Modifiability
|
||||
Efficiency (of the Lisp code at runtime)
|
||||
Architecture
|
||||
▶
|
||||
To build code that is robust and maintainable, it matters a lot how the code is divided into components, how these components communicate, how changes propagate as they evolve, and more importantly how the programmers who develop these components communicate as these components evolve.
|
||||
Using Libraries
|
||||
▶
|
||||
Often, the smallest hammer is to use an existing library. Or one that doesn't exist yet. In such cases, you are encouraged to use or develop such a library, but you must take appropriate precautions.
|
||||
Open-Sourcing Code
|
||||
▶
|
||||
|
||||
If you write a general-purpose library, or modify an existing open-source library, you are encouraged to publish the result separate from your main project and then have your project import it like any other open-source library.
|
||||
|
||||
Development Process
|
||||
▶
|
||||
Development process is outside the scope of this document. However, developers should remember at least these bits: get reviewed, write tests, eliminate warnings, run tests, avoid mass-changes.
|
||||
Formatting
|
||||
Spelling and Abbreviations
|
||||
▶
|
||||
|
||||
You must use correct spelling in your comments, and most importantly in your identifiers.
|
||||
|
||||
When several correct spellings exist (including American vs English), and there isn't a consensus amongst developers as which to use, you should choose the shorter spelling.
|
||||
|
||||
You must use only common and domain-specific abbreviations, and must be consistent with these abbreviations. You may abbreviate lexical variables of limited scope in order to avoid overly-long symbol names.
|
||||
|
||||
Line length
|
||||
▶
|
||||
You should format source code so that no line is longer than 100 characters.
|
||||
Indentation
|
||||
▶
|
||||
|
||||
Indent your code the way a properly configured GNU Emacs does.
|
||||
|
||||
Maintain a consistent indentation style throughout a project.
|
||||
|
||||
Indent carefully to make the code easier to understand.
|
||||
|
||||
File Header
|
||||
▶
|
||||
|
||||
You should include a description at the top of each source file.
|
||||
|
||||
You should include neither authorship nor copyright information in a source file.
|
||||
|
||||
Vertical white space
|
||||
▶
|
||||
Vertical white space: one blank line between top-level forms.
|
||||
Horizontal white space
|
||||
▶
|
||||
Horizontal white space: none around parentheses. No tabs.
|
||||
Documentation
|
||||
Document everything
|
||||
▶
|
||||
You should use document strings on all visible functions to explain how to use your code.
|
||||
Comment semicolons
|
||||
▶
|
||||
You must use the appropriate number of semicolons to introduce comments.
|
||||
Grammar and punctuation
|
||||
▶
|
||||
You should punctuate documentation correctly.
|
||||
Attention Required
|
||||
▶
|
||||
You must follow the convention of using TODO comments for code requiring special attention. For code using unobvious forms, you must include a comment.
|
||||
Domain-Specific Languages
|
||||
▶
|
||||
You should document DSLs and any terse program in a DSL.
|
||||
Naming
|
||||
Symbol guidelines
|
||||
▶
|
||||
You should use lower case. You should follow the rules for Spelling and Abbreviations You should follow punctuation conventions.
|
||||
Denote intent, not content
|
||||
▶
|
||||
Name your variables according to their intent, not their content.
|
||||
Global variables and constants
|
||||
▶
|
||||
Name globals according to convention.
|
||||
Predicate names
|
||||
▶
|
||||
Names of predicate functions and variables end with a "P".
|
||||
Omit library prefixes
|
||||
▶
|
||||
You should not include a library or package name as a prefix within the name of symbols.
|
||||
Packages
|
||||
▶
|
||||
Use packages appropriately.
|
||||
Language usage guidelines
|
||||
Mostly Functional Style
|
||||
▶
|
||||
You should avoid side-effects when they are not necessary.
|
||||
Recursion
|
||||
▶
|
||||
You should favor iteration over recursion.
|
||||
Special variables
|
||||
▶
|
||||
Use special variables sparingly.
|
||||
Assignment
|
||||
▶
|
||||
Be consistent in assignment forms.
|
||||
Assertions and Conditions
|
||||
▶
|
||||
You must make proper usage of assertions and conditions.
|
||||
Type Checking
|
||||
▶
|
||||
If you know the type of something, you should make it explicit in order to enable compile-time and run-time sanity-checking.
|
||||
CLOS
|
||||
▶
|
||||
Use CLOS appropriately.
|
||||
Meta-language guidelines
|
||||
Macros
|
||||
▶
|
||||
Use macros when appropriate, which is often. Define macros when appropriate, which is seldom.
|
||||
EVAL-WHEN
|
||||
▶
|
||||
When using EVAL-WHEN, you should almost always use all of (:compile-toplevel :load-toplevel :execute).
|
||||
Read-time evaluation
|
||||
▶
|
||||
You should use #. sparingly, and you must avoid read-time side-effects.
|
||||
EVAL
|
||||
▶
|
||||
You must not use EVAL at runtime.
|
||||
INTERN and UNINTERN
|
||||
▶
|
||||
You must not use INTERN or UNINTERN at runtime.
|
||||
Data Representation
|
||||
NIL: empty-list, false and I Don't Know
|
||||
▶
|
||||
Appropriately use or avoid using NIL.
|
||||
Do not abuse lists
|
||||
▶
|
||||
You must select proper data representation. You must not abuse the LIST data structure.
|
||||
Lists vs. structures vs. multiple values
|
||||
▶
|
||||
You should use the appropriate representation for product types.
|
||||
Lists vs. Pairs
|
||||
▶
|
||||
Use the appropriate functions when manipulating lists.
|
||||
Lists vs. Arrays
|
||||
▶
|
||||
You should use arrays rather than lists where random access matters.
|
||||
Lists vs. Sets
|
||||
▶
|
||||
You should only use lists as sets for very small lists.
|
||||
Proper Forms
|
||||
|
||||
You must follow the proper usage regarding well-known functions, macros and special forms.
|
||||
|
||||
Defining Constants
|
||||
▶
|
||||
You must use proper defining forms for constant values.
|
||||
Defining Functions
|
||||
▶
|
||||
You should make proper use of &OPTIONAL and &KEY arguments. You should not use &AUX arguments.
|
||||
Conditional Expressions
|
||||
▶
|
||||
Use the appropriate conditional form.
|
||||
Identity, Equality and Comparisons
|
||||
▶
|
||||
You should use the appropriate predicates when comparing objects.
|
||||
Iteration
|
||||
▶
|
||||
Use the appropriate form for iteration.
|
||||
I/O
|
||||
▶
|
||||
Use the appropriate I/O functions.
|
||||
Optimization
|
||||
Avoid Allocation
|
||||
▶
|
||||
You should avoid unnecessary allocation of memory.
|
||||
Unsafe Operations
|
||||
▶
|
||||
You must only use faster unsafe operations when there is a clear performance need and you can document why it's correct.
|
||||
DYNAMIC-EXTENT
|
||||
▶
|
||||
You should only use DYNAMIC-EXTENT where it matters for performance, and you can document why it is correct.
|
||||
REDUCE vs APPLY
|
||||
▶
|
||||
You should use REDUCE instead of APPLY where appropriate.
|
||||
Avoid NCONC
|
||||
▶
|
||||
You should not use NCONC; you should use APPEND instead, or better data structures.
|
||||
Pitfalls
|
||||
#'FUN vs. 'FUN
|
||||
▶
|
||||
You should usually refer to a function as #'FUN rather than 'FUN.
|
||||
Pathnames
|
||||
▶
|
||||
Common Lisp pathnames are tricky. Be aware of pitfalls. Use UIOP.
|
||||
SATISFIES
|
||||
▶
|
||||
You must be careful when using a SATISFIES clause in a type specifier.
|
||||
Credits: Adam Worrall, Dan Pierson, Matt Marjanovic, Matt Reklaitis, Paul Weiss, Scott McKay, Sundar Narasimhan, and several other people contributed. Special thanks to Steve Hain, and to the previous editors, in reverse chronological order Dan Weinreb and Jeremy Brown.
|
||||
|
||||
Revision 1.28
|
||||
|
||||
Robert Brown
|
||||
François-René Rideau
|
||||
17
ai/skills/markdown_expert/SKILL.md
Normal file
17
ai/skills/markdown_expert/SKILL.md
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: markdown_expert
|
||||
description: Google Developer Documentation Style Guide Expert. Use this to ensure all Markdown follow Google's official style guide.
|
||||
---
|
||||
# Markdown Expert
|
||||
|
||||
Expert in Google Developer Documentation Style Guide.
|
||||
|
||||
## Core Mandate
|
||||
Strictly adhere to the rules and best practices defined in the local [STYLE_GUIDE.md](./STYLE_GUIDE.md).
|
||||
|
||||
## Key Guidelines
|
||||
- **Clear & Concise Writing**: Favor simple sentence structures and active voice.
|
||||
- **Structural Integrity**: Use hierarchical headings correctly (H1, H2, H3).
|
||||
- **Semantic Markdown**: Use appropriate elements (lists, code blocks, tables) for clarity.
|
||||
- **Google Style**: Follow the local style guide precisely for all formatting and wording.
|
||||
- **Alerts & Callouts**: Use GitHub-style alerts (`> [!NOTE]`, `> [!IMPORTANT]`, etc.).
|
||||
650
ai/skills/markdown_expert/STYLE_GUIDE.md
Normal file
650
ai/skills/markdown_expert/STYLE_GUIDE.md
Normal file
@@ -0,0 +1,650 @@
|
||||
styleguide
|
||||
Markdown style guide
|
||||
|
||||
Much of what makes Markdown refreshing is the ability to write plain text and get great formatted output as a result. To keep the slate clean for the next author, your Markdown should be simple and consistent with the whole corpus wherever possible.
|
||||
|
||||
We seek to balance three goals:
|
||||
|
||||
Source text is readable and portable.
|
||||
The Markdown corpus is maintainable over time and across teams.
|
||||
The syntax is simple and easy to remember.
|
||||
|
||||
Contents:
|
||||
|
||||
Minimum viable documentation
|
||||
Better is better than best
|
||||
Capitalization
|
||||
Document layout
|
||||
Table of contents
|
||||
Character line limit
|
||||
Trailing whitespace
|
||||
Headings
|
||||
ATX-style headings
|
||||
Use unique, complete names for headings
|
||||
Add spacing to headings
|
||||
Use a single H1 heading
|
||||
Capitalization of titles and headers
|
||||
Lists
|
||||
Use lazy numbering for long lists
|
||||
Nested list spacing
|
||||
Code
|
||||
Inline
|
||||
Use code span for escaping
|
||||
Codeblocks
|
||||
Declare the language
|
||||
Escape newlines
|
||||
Use fenced code blocks instead of indented code blocks
|
||||
Nest codeblocks within lists
|
||||
Links
|
||||
Use explicit paths for links within Markdown
|
||||
Avoid relative paths unless within the same directory
|
||||
Use informative Markdown link titles
|
||||
Reference links
|
||||
Use reference links for long links
|
||||
Use reference links to reduce duplication
|
||||
Define reference links after their first use
|
||||
Images
|
||||
Tables
|
||||
Strongly prefer Markdown to HTML
|
||||
Minimum viable documentation
|
||||
|
||||
A small set of fresh and accurate docs is better than a sprawling, loose assembly of “documentation” in various states of disrepair.
|
||||
|
||||
The Markdown way encourages engineers to take ownership of their docs and keep them up to date with the same zeal we keep our tests in good order. Strive for this.
|
||||
|
||||
Identify what you really need: release docs, API docs, testing guidelines.
|
||||
Delete cruft frequently and in small batches.
|
||||
Better is better than best
|
||||
|
||||
The standards for an internal documentation review are different from the standards for code reviews. Reviewers should ask for improvements, but in general, the author should always be able to invoke the “Better/Best Rule.”
|
||||
|
||||
Fast iteration is your friend. To get long-term improvement, authors must stay productive when making short-term improvements. Set lower standards for each CL, so that more such CLs can happen.
|
||||
|
||||
As a reviewer of a documentation CL:
|
||||
|
||||
When reasonable, LGTM immediately and trust that comments will be fixed appropriately.
|
||||
Prefer to suggest an alternative rather than leaving a vague comment.
|
||||
For substantial changes, start your own follow-up CL instead. Especially try to avoid comments of the form “You should also…”.
|
||||
On rare occasions, hold up submission if the CL actually makes the docs worse. It’s okay to ask the author to revert.
|
||||
|
||||
As an author:
|
||||
|
||||
Avoid wasting cycles with trivial argument. Capitulate early and move on.
|
||||
Cite the Better/Best Rule as often as needed.
|
||||
Capitalization
|
||||
|
||||
Use the original names of products, tools and binaries, preserving the capitalization. E.g.:
|
||||
|
||||
# Markdown style guide
|
||||
|
||||
`Markdown` is a dead-simple platform for internal engineering documentation.
|
||||
|
||||
|
||||
and not
|
||||
|
||||
# markdown bad style guide example
|
||||
|
||||
`markdown` is a dead-simple platform for internal engineering documentation.
|
||||
|
||||
Document layout
|
||||
|
||||
In general, documents benefit from some variation of the following layout:
|
||||
|
||||
# Document Title
|
||||
|
||||
Short introduction.
|
||||
|
||||
[TOC]
|
||||
|
||||
## Topic
|
||||
|
||||
Content.
|
||||
|
||||
## See also
|
||||
|
||||
* https://link-to-more-info
|
||||
|
||||
|
||||
# Document title: The first heading should be a level-one heading, ideally the same or nearly the same as the filename. The first level-one heading is used as the page <title>.
|
||||
|
||||
author: Optional. If you’d like to claim ownership of the document or if you are very proud of it, add yourself under the title. However, revision history generally suffices.
|
||||
|
||||
Short introduction. 1–3 sentences providing a high-level overview of the topic. Imagine yourself as a complete newbie who landed on your “Extending Foo” doc and doesn’t know the most basic information you take for granted. “What is Foo? Why would I extend it?”
|
||||
|
||||
[TOC]: if you use hosting that supports table of contents, such as Gitiles, put [TOC] after the short introduction. See [TOC] documentation.
|
||||
|
||||
## Topic: The rest of your headings should start from level 2.
|
||||
|
||||
## See also: Put miscellaneous links at the bottom for the user who wants to know more or didn’t find what they needed.
|
||||
|
||||
Table of contents
|
||||
Use a [TOC] directive
|
||||
|
||||
Use a [TOC] directive unless all of your content is above the fold1 on a laptop.
|
||||
|
||||
Place the [TOC] directive after the introduction
|
||||
|
||||
Place the [TOC] directive after your page’s introduction and before the first H2 heading. For example:
|
||||
|
||||
# My Page
|
||||
|
||||
This is my introduction **before** the TOC.
|
||||
|
||||
[TOC]
|
||||
|
||||
## My first H2
|
||||
|
||||
# My Page
|
||||
|
||||
[TOC]
|
||||
|
||||
This is my introduction **after** the TOC where it should not be.
|
||||
|
||||
## My first H2
|
||||
|
||||
|
||||
For users who read your documentation visually, it doesn’t matter where your [TOC] directive is placed, as Markdown always displays the TOC toward the top and to the right of the page. However, [TOC] placement matters a lot when screen readers or keyboard controls are involved.
|
||||
|
||||
That’s because [TOC] inserts the HTML for the table of contents into the DOM wherever you’ve included the directive in your Markdown file. If, for example, you place the directive at the very bottom of your file, screen readers won’t read it until they get to the end of the document.
|
||||
|
||||
Character line limit
|
||||
|
||||
Markdown content follows the residual convention of an 80-character line limit. Why? Because it’s what most of us do for code.
|
||||
|
||||
Tooling integration: All our tooling is designed around code, so the more our documents are formatted according to similar rules, the better these tools will work. For example, Code Search doesn’t soft wrap.
|
||||
|
||||
Quality. The more engineers use their well-worn coding habits when creating and editing Markdown content, the better the quality. Markdown takes advantage of the excellent review culture we already have.
|
||||
|
||||
Exceptions
|
||||
|
||||
Exceptions to the 80-character rule include:
|
||||
|
||||
Links
|
||||
Tables
|
||||
Headings
|
||||
Code blocks
|
||||
|
||||
This means that lines with links are allowed to extend past column 80, along with any relevant punctuation:
|
||||
|
||||
* See the
|
||||
[foo docs](https://gerrit.googlesource.com/gitiles/+/HEAD/Documentation/markdown.md).
|
||||
and find the logfile.
|
||||
|
||||
|
||||
However, note that text before and after the link gets wrapped.
|
||||
|
||||
Tables may also run long. However, there are best practices for creating short, readable tables.
|
||||
|
||||
Foo | Bar | Baz
|
||||
----------------------------------------------------------------------------- | --- | ---
|
||||
Somehow-unavoidable-long-cell-filled-with-content-that-simply-refuses-to-wrap | Foo | Bar
|
||||
|
||||
Trailing whitespace
|
||||
|
||||
Don’t use trailing whitespace. Use a trailing backslash to break lines.
|
||||
|
||||
The CommonMark spec decrees that two spaces at the end of a line should insert a <br /> tag. However, many directories have a presubmit check for trailing whitespace, and many IDEs will clean it up anyway.
|
||||
|
||||
Use a trailing backslash, sparingly:
|
||||
|
||||
For some reason I just really want a break here,\
|
||||
though it's probably not necessary.
|
||||
|
||||
|
||||
Best practice is to avoid the need for a <br /> altogether. A pair of newlines will create a paragraph tag; get used to that.
|
||||
|
||||
Headings
|
||||
ATX-style headings
|
||||
# Heading 1
|
||||
|
||||
## Heading 2
|
||||
|
||||
|
||||
Headings with = or - underlines can be annoying to maintain and don’t fit with the rest of the heading syntax. An editor has to ask: Does --- mean H1 or H2?
|
||||
|
||||
Heading - do you remember what level? DO NOT DO THIS.
|
||||
---------
|
||||
|
||||
Use unique, complete names for headings
|
||||
|
||||
Use unique and fully descriptive names for each heading, even for sub-sections. Since link anchors are constructed from headings, this helps ensure that the automatically-constructed anchor links are intuitive and clear.
|
||||
|
||||
For example, instead of:
|
||||
|
||||
## Foo
|
||||
### Summary
|
||||
### Example
|
||||
## Bar
|
||||
### Summary
|
||||
### Example
|
||||
|
||||
|
||||
prefer:
|
||||
|
||||
## Foo
|
||||
### Foo summary
|
||||
### Foo example
|
||||
## Bar
|
||||
### Bar summary
|
||||
### Bar example
|
||||
|
||||
Add spacing to headings
|
||||
|
||||
Prefer spacing after # and newlines before and after:
|
||||
|
||||
...text before.
|
||||
|
||||
## Heading 2
|
||||
|
||||
Text after...
|
||||
|
||||
|
||||
Lack of spacing makes it a little harder to read in source:
|
||||
|
||||
...text before.
|
||||
|
||||
##Heading 2
|
||||
Text after... DO NOT DO THIS.
|
||||
|
||||
Use a single H1 heading
|
||||
|
||||
Use one H1 heading as the title of your document. Subsequent headings should be H2 or deeper. See Document layout for more information.
|
||||
|
||||
Capitalization of titles and headers
|
||||
|
||||
Follow the guidance for capitalization in the Google Developer Documentation Style Guide.
|
||||
|
||||
Lists
|
||||
Use lazy numbering for long lists
|
||||
|
||||
Markdown is smart enough to let the resulting HTML render your numbered lists correctly. For longer lists that may change, especially long nested lists, use “lazy” numbering:
|
||||
|
||||
1. Foo.
|
||||
1. Bar.
|
||||
1. Foofoo.
|
||||
1. Barbar.
|
||||
1. Baz.
|
||||
|
||||
|
||||
However, if the list is small and you don’t anticipate changing it, prefer fully numbered lists, because it’s nicer to read in source:
|
||||
|
||||
1. Foo.
|
||||
2. Bar.
|
||||
3. Baz.
|
||||
|
||||
Nested list spacing
|
||||
|
||||
When nesting lists, use a 4-space indent for both numbered and bulleted lists:
|
||||
|
||||
1. Use 2 spaces after the item number, so the text itself is indented 4 spaces.
|
||||
Use a 4-space indent for wrapped text.
|
||||
2. Use 2 spaces again for the next item.
|
||||
|
||||
* Use 3 spaces after a bullet, so the text itself is indented 4 spaces.
|
||||
Use a 4-space indent for wrapped text.
|
||||
1. Use 2 spaces with numbered lists, as before.
|
||||
Wrapped text in a nested list needs an 8-space indent.
|
||||
2. Looks nice, doesn't it?
|
||||
* Back to the bulleted list, indented 3 spaces.
|
||||
|
||||
|
||||
The following works, but it’s very messy:
|
||||
|
||||
* One space,
|
||||
with no indent for wrapped text.
|
||||
1. Irregular nesting... DO NOT DO THIS.
|
||||
|
||||
|
||||
Even when there’s no nesting, using the 4 space indent makes layout consistent for wrapped text:
|
||||
|
||||
* Foo,
|
||||
wrapped with a 4-space indent.
|
||||
|
||||
1. Two spaces for the list item
|
||||
and 4 spaces before wrapped text.
|
||||
2. Back to 2 spaces.
|
||||
|
||||
|
||||
However, when lists are small, not nested, and a single line, one space can suffice for both kinds of lists:
|
||||
|
||||
* Foo
|
||||
* Bar
|
||||
* Baz.
|
||||
|
||||
1. Foo.
|
||||
2. Bar.
|
||||
|
||||
Code
|
||||
Inline
|
||||
|
||||
`Backticks` designate inline code that will be rendered literally. Use them for short code quotations, field names, and more:
|
||||
|
||||
You'll want to run `really_cool_script.sh arg`.
|
||||
|
||||
Pay attention to the `foo_bar_whammy` field in that table.
|
||||
|
||||
|
||||
Use inline code when referring to file types in a generic sense, rather than a specific existing file:
|
||||
|
||||
Be sure to update your `README.md`!
|
||||
|
||||
Use code span for escaping
|
||||
|
||||
When you don’t want text to be processed as normal Markdown, like a fake path or example URL that would lead to a bad autolink, wrap it in backticks:
|
||||
|
||||
An example Markdown shortlink would be: `Markdown/foo/Markdown/bar.md`
|
||||
|
||||
An example query might be: `https://www.google.com/search?q=$TERM`
|
||||
|
||||
Codeblocks
|
||||
|
||||
For code quotations longer than a single line, use a fenced code block:
|
||||
|
||||
```python
|
||||
def Foo(self, bar):
|
||||
self.bar = bar
|
||||
```
|
||||
|
||||
Declare the language
|
||||
|
||||
It is best practice to explicitly declare the language, so that neither the syntax highlighter nor the next editor must guess.
|
||||
|
||||
Use fenced code blocks instead of indented code blocks
|
||||
|
||||
Four-space indenting is also interpreted as a code block. However, we strongly recommend fencing for all code blocks.
|
||||
|
||||
Indented code blocks can sometimes look cleaner in the source, but they have several drawbacks:
|
||||
|
||||
You cannot specify the language. Some Markdown features are tied to language specifiers.
|
||||
The beginning and end of the code block are ambiguous.
|
||||
Indented code blocks are harder to search for in Code Search.
|
||||
You'll need to run:
|
||||
|
||||
bazel run :thing -- --foo
|
||||
|
||||
And then:
|
||||
|
||||
bazel run :another_thing -- --bar
|
||||
|
||||
And again:
|
||||
|
||||
bazel run :yet_again -- --baz
|
||||
|
||||
Escape newlines
|
||||
|
||||
Because most command-line snippets are intended to be copied and pasted directly into a terminal, it’s best practice to escape any newlines. Use a single backslash at the end of the line:
|
||||
|
||||
```shell
|
||||
$ bazel run :target -- --flag --foo=longlonglonglonglongvalue \
|
||||
--bar=anotherlonglonglonglonglonglonglonglonglonglongvalue
|
||||
```
|
||||
|
||||
Nest codeblocks within lists
|
||||
|
||||
If you need a code block within a list, make sure to indent it so as to not break the list:
|
||||
|
||||
* Bullet.
|
||||
|
||||
```c++
|
||||
int foo;
|
||||
```
|
||||
|
||||
* Next bullet.
|
||||
|
||||
|
||||
You can also create a nested code block with 4 spaces. Simply indent 4 additional spaces from the list indentation:
|
||||
|
||||
* Bullet.
|
||||
|
||||
int foo;
|
||||
|
||||
* Next bullet.
|
||||
|
||||
Links
|
||||
|
||||
Long links make source Markdown difficult to read and break the 80 character wrapping. Wherever possible, shorten your links.
|
||||
|
||||
Use explicit paths for links within Markdown
|
||||
|
||||
Use the explicit path for Markdown links. For example:
|
||||
|
||||
[...](/path/to/other/markdown/page.md)
|
||||
|
||||
|
||||
You don’t need to use the entire qualified URL:
|
||||
|
||||
[...](https://bad-full-url.example.com/path/to/other/markdown/page.md)
|
||||
|
||||
Avoid relative paths unless within the same directory
|
||||
|
||||
Relative paths are fairly safe within the same directory. For example:
|
||||
|
||||
[...](other-page-in-same-dir.md)
|
||||
[...](/path/to/another/dir/other-page.md)
|
||||
|
||||
|
||||
Avoid relative links if you need to specify other directories with ../:
|
||||
|
||||
[...](../../bad/path/to/another/dir/other-page.md)
|
||||
|
||||
Use informative Markdown link titles
|
||||
|
||||
Markdown link syntax allows you to set a link title. Use it wisely. Users often do not read documents; they scan them.
|
||||
|
||||
Links catch the eye. But titling your links “here,” “link,” or simply duplicating the target URL tells the hasty reader precisely nothing and is a waste of space:
|
||||
|
||||
DO NOT DO THIS.
|
||||
|
||||
See the Markdown guide for more info: [link](markdown.md), or check out the
|
||||
style guide [here](/styleguide/docguide/style.html).
|
||||
|
||||
Check out a typical test result:
|
||||
[https://example.com/foo/bar](https://example.com/foo/bar).
|
||||
|
||||
|
||||
Instead, write the sentence naturally, then go back and wrap the most appropriate phrase with the link:
|
||||
|
||||
See the [Markdown guide](markdown.md) for more info, or check out the
|
||||
[style guide](/styleguide/docguide/style.html).
|
||||
|
||||
Check out a
|
||||
[typical test result](https://example.com/foo/bar).
|
||||
|
||||
Reference
|
||||
|
||||
For long links or image URLs, you may want to split the link use from the link definition, like this:
|
||||
|
||||
See the [Markdown style guide][style], which has suggestions for making docs more
|
||||
readable.
|
||||
|
||||
[style]: http://Markdown/corp/Markdown/docs/reference/style.md
|
||||
|
||||
Use reference links for long links
|
||||
|
||||
Use reference links where the length of the link would detract from the readability of the surrounding text if it were inlined. Reference links make it harder to see the destination of a link in source text, and add additional syntax.
|
||||
|
||||
In this example, reference link usage is not appropriate, because the link is not long enough to disrupt the flow of the text:
|
||||
|
||||
DO NOT DO THIS.
|
||||
|
||||
The [style guide][style_guide] says not to use reference links unless you have
|
||||
to.
|
||||
|
||||
[style_guide]: https://google.com/Markdown-style
|
||||
|
||||
|
||||
Just inline it instead:
|
||||
|
||||
https://google.com/Markdown-style says not to use reference links unless you have to.
|
||||
|
||||
|
||||
In this example, the link destination is long enough that it makes sense to use a reference link:
|
||||
|
||||
The [style guide] says not to use reference links unless you have to.
|
||||
|
||||
[style guide]: https://docs.google.com/document/d/13HQBxfhCwx8lVRuN2Wf6poqvAfVeEXmFVcawP5I6B3c/edit
|
||||
|
||||
|
||||
Use reference links more often in tables. It is particularly important to keep table content short, since Markdown does not provide a facility to break text in cell tables across multiple lines, and smaller tables are more readable.
|
||||
|
||||
For example, this table’s readability is worsened by inline links:
|
||||
|
||||
DO NOT DO THIS.
|
||||
|
||||
Site | Description
|
||||
---------------------------------------------------------------- | -----------------------
|
||||
[site 1](http://google.com/excessively/long/path/example_site_1) | This is example site 1.
|
||||
[site 2](http://google.com/excessively/long/path/example_site_2) | This is example site 2.
|
||||
|
||||
|
||||
Instead, use reference links to keep the line length manageable:
|
||||
|
||||
Site | Description
|
||||
-------- | -----------------------
|
||||
[site 1] | This is example site 1.
|
||||
[site 2] | This is example site 2.
|
||||
|
||||
[site 1]: http://google.com/excessively/long/path/example_site_1
|
||||
[site 2]: http://google.com/excessively/long/path/example_site_2
|
||||
|
||||
Use reference links to reduce duplication
|
||||
|
||||
Consider using reference links when referencing the same link destination multiple times in a document, to reduce duplication.
|
||||
|
||||
Define reference links after their first use
|
||||
|
||||
We recommend putting reference link definitions just before the next heading, at the end of the section in which they’re first used. If your editor has its own opinion about where they should go, don’t fight it; the tools always win.
|
||||
|
||||
We define a “section” as all text between two headings. Think of reference links like footnotes, and the current section like the current page.
|
||||
|
||||
This arrangement makes it easy to find the link destination in source view, while keeping the flow of text free from clutter. In long documents with lots of reference links, it also prevents “footnote overload” at the bottom of the file, which makes it difficult to pick out the relevant link destination.
|
||||
|
||||
There is one exception to this rule: reference link definitions that are used in multiple sections should go at the end of the document. This avoids dangling links when a section is updated or moved.
|
||||
|
||||
In the following example, the reference definition is far from its initial use, which makes the document harder to read:
|
||||
|
||||
# Header FOR A BAD DOCUMENT
|
||||
|
||||
Some text with a [link][link_def].
|
||||
|
||||
Some more text with the same [link][link_def].
|
||||
|
||||
## Header 2
|
||||
|
||||
... lots of text ...
|
||||
|
||||
## Header 3
|
||||
|
||||
Some more text using a [different_link][different_link_def].
|
||||
|
||||
[link_def]: http://reallyreallyreallylonglink.com
|
||||
[different_link_def]: http://differentreallyreallylonglink.com
|
||||
|
||||
|
||||
Instead, put it just before the header following its first use:
|
||||
|
||||
# Header
|
||||
|
||||
Some text with a [link][link_def].
|
||||
|
||||
Some more text with the same [link][link_def].
|
||||
|
||||
[link_def]: http://reallyreallyreallylonglink.com
|
||||
|
||||
## Header 2
|
||||
|
||||
... lots of text ...
|
||||
|
||||
## Header 3
|
||||
|
||||
Some more text using a [different_link][different_link_def].
|
||||
|
||||
[different_link_def]: http://differentreallyreallylonglink.com
|
||||
|
||||
Images
|
||||
|
||||
See image syntax.
|
||||
|
||||
Use images sparingly, and prefer simple screenshots. This guide is designed around the idea that plain text gets users down to the business of communication faster with less reader distraction and author procrastination. However, it’s sometimes very helpful to show what you mean.
|
||||
|
||||
Use images when it’s easier to show a reader something than to describe it. For example, explaining how to navigate a UI is often easier with an image than text.
|
||||
Make sure to provide appropriate text to describe your image. Readers who are not sighted cannot see your image and still need to understand the content! See the alt text best practices below.
|
||||
Tables
|
||||
|
||||
Use tables when they make sense: for the presentation of tabular data that needs to be scanned quickly.
|
||||
|
||||
Avoid using tables when your data could easily be presented in a list. Lists are much easier to write and read in Markdown.
|
||||
|
||||
For example:
|
||||
|
||||
DO NOT DO THIS
|
||||
|
||||
Fruit | Metrics | Grows on | Acute curvature | Attributes | Notes
|
||||
------ | ------------ | -------- | ------------------ | ----------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------
|
||||
Apple | Very popular | Trees | | [Juicy](http://cs/SomeReallyReallyReallyReallyReallyReallyReallyReallyLongQuery), Firm, Sweet | Apples keep doctors away.
|
||||
Banana | Very popular | Trees | 16 degrees average | [Convenient](http://cs/SomeDifferentReallyReallyReallyReallyReallyReallyReallyReallyLongQuery), Soft, Sweet | Contrary to popular belief, most apes prefer mangoes. Don't you? See the [design doc][banana_v2] for the newest hotness in bananiels.
|
||||
|
||||
|
||||
This table illustrates a few typical problems:
|
||||
|
||||
Poor distribution: Several columns don’t differ across rows, and some cells are empty. This is usually a sign that your data may not benefit from tabular display.
|
||||
|
||||
Unbalanced dimensions: There are a small number of rows relative to columns. When this ratio is unbalanced in either direction, a table becomes little more than an inflexible format for text.
|
||||
|
||||
Rambling prose in some cells. Tables should tell a succinct story at a glance.
|
||||
|
||||
Lists and subheadings sometimes suffice to present the same information. Let’s see this data in list form:
|
||||
|
||||
## Fruits
|
||||
|
||||
Both types are highly popular, sweet, and grow on trees.
|
||||
|
||||
### Apple
|
||||
|
||||
* [Juicy](http://SomeReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongURL)
|
||||
* Firm
|
||||
|
||||
Apples keep doctors away.
|
||||
|
||||
### Banana
|
||||
|
||||
* [Convenient](http://cs/SomeDifferentReallyReallyReallyReallyReallyReallyReallyReallyLongQuery)
|
||||
* Soft
|
||||
* 16 degrees average acute curvature.
|
||||
|
||||
Contrary to popular belief, most apes prefer mangoes. Don't you?
|
||||
|
||||
See the [design doc][banana_v2] for the newest hotness in bananiels.
|
||||
|
||||
|
||||
The list form is more spacious, and arguably therefore much easier for the reader to find what interests her in this case.
|
||||
|
||||
However, there are times a table is the best choice. When you have:
|
||||
|
||||
Relatively uniform data distribution across two dimensions.
|
||||
Many parallel items with distinct attributes.
|
||||
|
||||
In those cases, a table format is just the thing. In fact, a compact table can improve readability:
|
||||
|
||||
Transport | Favored by | Advantages
|
||||
---------------- | -------------- | -----------------------------------------------
|
||||
Swallow | Coconuts | [Fast when unladen][airspeed]
|
||||
Bicycle | Miss Gulch | [Weatherproof][tornado_proofing]
|
||||
X-34 landspeeder | Whiny farmboys | [Cheap][tosche_station] since the XP-38 came out
|
||||
|
||||
[airspeed]: http://google3/airspeed.h
|
||||
[tornado_proofing]: http://google3/kansas/
|
||||
[tosche_station]: http://google3/power_converter.h
|
||||
|
||||
|
||||
Note that reference links are used to keep the table cells manageable.
|
||||
|
||||
Strongly prefer Markdown to HTML
|
||||
|
||||
Please prefer standard Markdown syntax wherever possible and avoid HTML hacks. If you can’t seem to accomplish what you want, reconsider whether you really need it. Except for big tables, Markdown meets almost all needs already.
|
||||
|
||||
Every bit of HTML hacking reduces the readability and portability of our Markdown corpus. This in turn limits the usefulness of integrations with other tools, which may either present the source as plain text or render it. See Philosophy.
|
||||
|
||||
Gitiles does not render HTML.
|
||||
|
||||
Content is “above the fold” if it is visible when the page is first displayed. Content is “below the fold” if it is hidden until the user scrolls down the page on a computer or literally unfolds a document such as a newspaper. ↩
|
||||
16
ai/skills/shell_expert/SKILL.md
Normal file
16
ai/skills/shell_expert/SKILL.md
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
name: shell_expert
|
||||
description: Google Shell Style Guide Expert. For robust and maintainable bash/sh scripts.
|
||||
---
|
||||
# Shell Expert
|
||||
|
||||
Expert in Google Shell Style Guide.
|
||||
|
||||
## Core Mandate
|
||||
Strictly follow [STYLE_GUIDE.md](./STYLE_GUIDE.md).
|
||||
|
||||
## Key Principles
|
||||
- Always quote variables.
|
||||
- Use [[ for testing.
|
||||
- Prefer over backticks.
|
||||
- Proper error handling (set -e).
|
||||
948
ai/skills/shell_expert/STYLE_GUIDE.md
Normal file
948
ai/skills/shell_expert/STYLE_GUIDE.md
Normal file
@@ -0,0 +1,948 @@
|
||||
styleguide
|
||||
Shell Style Guide
|
||||
|
||||
Authored, revised and maintained by many Googlers.
|
||||
|
||||
Table of Contents
|
||||
Section Contents
|
||||
Background Which Shell to Use - When to use Shell
|
||||
Shell Files and Interpreter Invocation File Extensions - SUID/SGID
|
||||
Environment STDOUT vs STDERR
|
||||
Comments File Header - Function Comments - Implementation Comments - TODO Comments
|
||||
Formatting Indentation - Line Length and Long Strings - Pipelines - Control Flow - Case statement - Variable expansion - Quoting
|
||||
Features and Bugs ShellCheck - Command Substitution - Test, [… ], and [[… ]] - Testing Strings - Wildcard Expansion of Filenames - Eval - Arrays - Pipes to While - Arithmetic - Aliases
|
||||
Naming Conventions Function Names - Variable Names - Constants and Environment Variable Names - Source Filenames - Use Local Variables - Function Location - main
|
||||
Calling Commands Checking Return Values - Builtin Commands vs. External Commands
|
||||
When in Doubt: Be Consistent
|
||||
|
||||
Background
|
||||
|
||||
Which Shell to Use
|
||||
|
||||
Bash is the only shell scripting language permitted for executables.
|
||||
|
||||
Executables must start with #!/bin/bash and minimal flags. Use set to set shell options so that calling your script as bash script_name does not break its functionality.
|
||||
|
||||
Restricting all executable shell scripts to bash gives us a consistent shell language that’s installed on all our machines. In particular, this means there is generally no need to strive for POSIX-compatibility or otherwise avoid “bashisms”.
|
||||
|
||||
The only exception to the above is where you’re forced to by whatever you’re coding for. For example some legacy operating systems or constrained execution environments may require plain Bourne shell for certain scripts.
|
||||
|
||||
When to use Shell
|
||||
|
||||
Shell should only be used for small utilities or simple wrapper scripts.
|
||||
|
||||
While shell scripting isn’t a development language, it is used for writing various utility scripts throughout Google. This style guide is more a recognition of its use rather than a suggestion that it be used for widespread deployment.
|
||||
|
||||
Some guidelines:
|
||||
|
||||
If you’re mostly calling other utilities and are doing relatively little data manipulation, shell is an acceptable choice for the task.
|
||||
If performance matters, use something other than shell.
|
||||
If you are writing a script that is more than 100 lines long, or that uses non-straightforward control flow logic, you should rewrite it in a more structured language now. Bear in mind that scripts grow. Rewrite your script early to avoid a more time-consuming rewrite at a later date.
|
||||
When assessing the complexity of your code (e.g. to decide whether to switch languages) consider whether the code is easily maintainable by people other than its author.
|
||||
|
||||
Shell Files and Interpreter Invocation
|
||||
|
||||
File Extensions
|
||||
|
||||
Executables should have a .sh extension or no extension.
|
||||
|
||||
If the executable will have a build rule that renames the source file then prefer to use a .sh extension. This enables you to use the recommended naming convention, with a source file like foo.sh and a build rule named foo.
|
||||
If the executable will be added directly to the user’s PATH, then prefer to use no extension. It is not necessary to know what language a program is written in when executing it and shell doesn’t require an extension so we prefer not to use one for executables that will be directly invoked by users. At the same time, consider whether it is preferable to deploy the output of a build rule rather than deploying the source file directly.
|
||||
If neither of the above apply, then either choice is acceptable.
|
||||
|
||||
Libraries must have a .sh extension and should not be executable.
|
||||
|
||||
SUID/SGID
|
||||
|
||||
SUID and SGID are forbidden on shell scripts.
|
||||
|
||||
There are too many security issues with shell that make it nearly impossible to secure sufficiently to allow SUID/SGID. While bash does make it difficult to run SUID, it’s still possible on some platforms which is why we’re being explicit about banning it.
|
||||
|
||||
Use sudo to provide elevated access if you need it.
|
||||
|
||||
Environment
|
||||
|
||||
STDOUT vs STDERR
|
||||
|
||||
All error messages should go to STDERR.
|
||||
|
||||
This makes it easier to separate normal status from actual issues.
|
||||
|
||||
A function to print out error messages along with other status information is recommended.
|
||||
|
||||
err() {
|
||||
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
|
||||
}
|
||||
|
||||
if ! do_something; then
|
||||
err "Unable to do_something"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
Comments
|
||||
|
||||
File Header
|
||||
|
||||
Start each file with a description of its contents.
|
||||
|
||||
Every file must have a top-level comment including a brief overview of its contents. A copyright notice and author information are optional.
|
||||
|
||||
Example:
|
||||
|
||||
#!/bin/bash
|
||||
#
|
||||
# Perform hot backups of Oracle databases.
|
||||
|
||||
|
||||
Function Comments
|
||||
|
||||
Any function that is not both obvious and short must have a function header comment. Any function in a library must have a function header comment regardless of length or complexity.
|
||||
|
||||
It should be possible for someone else to learn how to use your program or to use a function in your library by reading the comments (and self-help, if provided) without reading the code.
|
||||
|
||||
All function header comments should describe the intended API behaviour using:
|
||||
|
||||
Description of the function.
|
||||
Globals: List of global variables used and modified.
|
||||
Arguments: Arguments taken.
|
||||
Outputs: Output to STDOUT or STDERR.
|
||||
Returns: Returned values other than the default exit status of the last command run.
|
||||
|
||||
Example:
|
||||
|
||||
#######################################
|
||||
# Cleanup files from the backup directory.
|
||||
# Globals:
|
||||
# BACKUP_DIR
|
||||
# ORACLE_SID
|
||||
# Arguments:
|
||||
# None
|
||||
#######################################
|
||||
function cleanup() {
|
||||
…
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Get configuration directory.
|
||||
# Globals:
|
||||
# SOMEDIR
|
||||
# Arguments:
|
||||
# None
|
||||
# Outputs:
|
||||
# Writes location to stdout
|
||||
#######################################
|
||||
function get_dir() {
|
||||
echo "${SOMEDIR}"
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Delete a file in a sophisticated manner.
|
||||
# Arguments:
|
||||
# File to delete, a path.
|
||||
# Returns:
|
||||
# 0 if thing was deleted, non-zero on error.
|
||||
#######################################
|
||||
function del_thing() {
|
||||
rm "$1"
|
||||
}
|
||||
|
||||
|
||||
Implementation Comments
|
||||
|
||||
Comment tricky, non-obvious, interesting or important parts of your code.
|
||||
|
||||
This follows general Google coding comment practice. Don’t comment everything. If there’s a complex algorithm or you’re doing something out of the ordinary, put a short comment in.
|
||||
|
||||
TODO Comments
|
||||
|
||||
Use TODO comments for code that is temporary, a short-term solution, or good-enough but not perfect.
|
||||
|
||||
This matches the convention in the C++ Guide.
|
||||
|
||||
TODOs should include the string TODO in all caps, followed by the name, e-mail address, or other identifier of the person with the best context about the problem referenced by the TODO. The main purpose is to have a consistent TODO that can be searched to find out how to get more details upon request. A TODO is not a commitment that the person referenced will fix the problem. Thus when you create a TODO, it is almost always your name that is given.
|
||||
|
||||
Examples:
|
||||
|
||||
# TODO(mrmonkey): Handle the unlikely edge cases (bug ####)
|
||||
|
||||
|
||||
Formatting
|
||||
|
||||
While you should follow the style that’s already there for files that you’re modifying, the following are required for any new code.
|
||||
|
||||
Indentation
|
||||
|
||||
Indent 2 spaces. No tabs.
|
||||
|
||||
Use blank lines between blocks to improve readability. Indentation is two spaces. Whatever you do, don’t use tabs. For existing files, stay faithful to the existing indentation.
|
||||
|
||||
Exception: The only exception for using tabs is for the body of <<- tab-indented here-document.
|
||||
|
||||
Line Length and Long Strings
|
||||
|
||||
Maximum line length is 80 characters.
|
||||
|
||||
If you have to write literal strings that are longer than 80 characters, this should be done with a here document or an embedded newline if possible.
|
||||
|
||||
Words that are longer than 80 chars and can’t sensibly be split are ok, but where possible these items should be on a line of their own, or factored into a variable. Examples include file paths and URLs, particularly where string-matching them (such as grep) is valuable for maintenance.
|
||||
|
||||
# DO use 'here document's
|
||||
cat <<END
|
||||
I am an exceptionally long
|
||||
string.
|
||||
END
|
||||
|
||||
# Embedded newlines are ok too
|
||||
long_string="I am an exceptionally
|
||||
long string."
|
||||
|
||||
long_file="/i/am/an/exceptionally/loooooooooooooooooooooooooooooooooooooooooooooooooooong_file"
|
||||
|
||||
long_string_with_long_file="i am including an exceptionally \
|
||||
/very/long/file\
|
||||
in this long string."
|
||||
|
||||
# Long file converted into a shorter variable name with cleaner line breaking.
|
||||
long_string_alt="i am an including an exceptionally ${long_file} in this long\
|
||||
string"
|
||||
|
||||
# Just because a line contains an exception doesn't mean the rest of the
|
||||
# line shouldn't be wrapped like usual.
|
||||
|
||||
bad_long_string_with_long_file="i am including an exceptionally /very/long/file in this long string."
|
||||
|
||||
|
||||
Pipelines
|
||||
|
||||
Pipelines should be split one per line if they don’t all fit on one line.
|
||||
|
||||
If a pipeline all fits on one line, it should be on one line.
|
||||
|
||||
If not, it should be split at one pipe segment per line with the pipe on the newline and a 2 space indent for the next section of the pipe. \ should be consistently used to indicate line continuation. This applies to a chain of commands combined using | as well as to logical compounds using || and &&.
|
||||
|
||||
# All fits on one line
|
||||
command1 | command2
|
||||
|
||||
# Long commands
|
||||
command1 \
|
||||
| command2 \
|
||||
| command3 \
|
||||
| command4
|
||||
|
||||
|
||||
This helps readability when distinguishing a pipeline from a regular long command continuation, particularly if the line is using both.
|
||||
|
||||
Comments will need to precede the whole pipeline. If the comment and pipeline are large and complex, then it is worth considering moving low level details of them aside by using a helper function.
|
||||
|
||||
Control Flow
|
||||
|
||||
Put ; then and ; do on the same line as the if, for, or while.
|
||||
|
||||
Control flow statements in shell are a bit different, but we follow the same principles as with braces when declaring functions. That is: ; then and ; do should be on the same line as the if/for/while/until/select. else should be on its own line and closing statements (fi and done) should be on their own line vertically aligned with the opening statement.
|
||||
|
||||
Example:
|
||||
|
||||
# If inside a function remember to declare the loop variable as
|
||||
# a local to avoid it leaking into the global environment:
|
||||
local dir
|
||||
for dir in "${dirs_to_cleanup[@]}"; do
|
||||
if [[ -d "${dir}/${SESSION_ID}" ]]; then
|
||||
log_date "Cleaning up old files in ${dir}/${SESSION_ID}"
|
||||
rm "${dir}/${SESSION_ID}/"* || error_message
|
||||
else
|
||||
mkdir -p "${dir}/${SESSION_ID}" || error_message
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
Although it is possible to omit in "$@" in for loops we recommend consistently including it for clarity.
|
||||
|
||||
for arg in "$@"; do
|
||||
echo "argument: ${arg}"
|
||||
done
|
||||
|
||||
|
||||
Case statement
|
||||
Indent alternatives by 2 spaces.
|
||||
A one-line alternative needs a space after the close parenthesis of the pattern and before the ;;.
|
||||
Long or multi-command alternatives should be split over multiple lines with the pattern, actions, and ;; on separate lines.
|
||||
|
||||
The matching expressions are indented one level from the case and esac. Multiline actions are indented another level. In general, there is no need to quote match expressions. Pattern expressions should not be preceded by an open parenthesis. Avoid the ;& and ;;& notations.
|
||||
|
||||
case "${expression}" in
|
||||
a)
|
||||
variable="…"
|
||||
some_command "${variable}" "${other_expr}" …
|
||||
;;
|
||||
absolute)
|
||||
actions="relative"
|
||||
another_command "${actions}" "${other_expr}" …
|
||||
;;
|
||||
*)
|
||||
error "Unexpected expression '${expression}'"
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
Simple commands may be put on the same line as the pattern and ;; as long as the expression remains readable. This is often appropriate for single-letter option processing. When the actions don’t fit on a single line, put the pattern on a line on its own, then the actions, then ;; also on a line of its own. When on the same line as the actions, use a space after the close parenthesis of the pattern and another before the ;;.
|
||||
|
||||
verbose='false'
|
||||
aflag=''
|
||||
bflag=''
|
||||
files=''
|
||||
while getopts 'abf:v' flag; do
|
||||
case "${flag}" in
|
||||
a) aflag='true' ;;
|
||||
b) bflag='true' ;;
|
||||
f) files="${OPTARG}" ;;
|
||||
v) verbose='true' ;;
|
||||
*) error "Unexpected option ${flag}" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
Variable expansion
|
||||
|
||||
In order of precedence: Stay consistent with what you find; quote your variables; prefer "${var}" over "$var".
|
||||
|
||||
These are strongly recommended guidelines but not mandatory regulation. Nonetheless, the fact that it’s a recommendation and not mandatory doesn’t mean it should be taken lightly or downplayed.
|
||||
|
||||
They are listed in order of precedence.
|
||||
|
||||
Stay consistent with what you find for existing code.
|
||||
Quote variables, see Quoting section below.
|
||||
Don’t brace-delimit single character shell specials / positional parameters, unless strictly necessary or avoiding deep confusion.
|
||||
|
||||
Prefer brace-delimiting all other variables.
|
||||
|
||||
# Section of *recommended* cases.
|
||||
|
||||
# Preferred style for 'special' variables:
|
||||
echo "Positional: $1" "$5" "$3"
|
||||
echo "Specials: !=$!, -=$-, _=$_. ?=$?, #=$# *=$* @=$@ \$=$$ …"
|
||||
|
||||
# Braces necessary:
|
||||
echo "many parameters: ${10}"
|
||||
|
||||
# Braces avoiding confusion:
|
||||
# Output is "a0b0c0"
|
||||
set -- a b c
|
||||
echo "${1}0${2}0${3}0"
|
||||
|
||||
# Preferred style for other variables:
|
||||
echo "PATH=${PATH}, PWD=${PWD}, mine=${some_var}"
|
||||
while read -r f; do
|
||||
echo "file=${f}"
|
||||
done < <(find /tmp)
|
||||
|
||||
# Section of *discouraged* cases
|
||||
|
||||
# Unquoted vars, unbraced vars, brace-delimited single letter
|
||||
# shell specials.
|
||||
echo a=$avar "b=$bvar" "PID=${$}" "${1}"
|
||||
|
||||
# Confusing use: this is expanded as "${1}0${2}0${3}0",
|
||||
# not "${10}${20}${30}
|
||||
set -- a b c
|
||||
echo "$10$20$30"
|
||||
|
||||
|
||||
NOTE: Using braces in ${var} is not a form of quoting. “Double quotes” must be used as well.
|
||||
|
||||
Quoting
|
||||
Always quote strings containing variables, command substitutions, spaces or shell meta characters, unless careful unquoted expansion is required or it’s a shell-internal integer (see next point).
|
||||
Use arrays for safe quoting of lists of elements, especially command-line flags. See Arrays below.
|
||||
Optionally quote shell-internal, readonly special variables that are defined to be integers: $?, $#, $$, $!. Prefer quoting of “named” internal integer variables, e.g. PPID etc for consistency.
|
||||
Prefer quoting strings that are “words” (as opposed to command options or path names).
|
||||
Be aware of the quoting rules for pattern matches in [[ … ]]. See the Test, [ … ], and [[ … ]] section below.
|
||||
Use "$@" unless you have a specific reason to use $*, such as simply appending the arguments to a string in a message or log.
|
||||
# 'Single' quotes indicate that no substitution is desired.
|
||||
# "Double" quotes indicate that substitution is required/tolerated.
|
||||
|
||||
# Simple examples
|
||||
|
||||
# "quote command substitutions"
|
||||
# Note that quotes nested inside "$()" don't need escaping.
|
||||
flag="$(some_command and its args "$@" 'quoted separately')"
|
||||
|
||||
# "quote variables"
|
||||
echo "${flag}"
|
||||
|
||||
# Use arrays with quoted expansion for lists.
|
||||
declare -a FLAGS
|
||||
FLAGS=( --foo --bar='baz' )
|
||||
readonly FLAGS
|
||||
mybinary "${FLAGS[@]}"
|
||||
|
||||
# It's ok to not quote internal integer variables.
|
||||
if (( $# > 3 )); then
|
||||
echo "ppid=${PPID}"
|
||||
fi
|
||||
|
||||
# "never quote literal integers"
|
||||
value=32
|
||||
# "quote command substitutions", even when you expect integers
|
||||
number="$(generate_number)"
|
||||
|
||||
# "prefer quoting words", not compulsory
|
||||
readonly USE_INTEGER='true'
|
||||
|
||||
# "quote shell meta characters"
|
||||
echo 'Hello stranger, and well met. Earn lots of $$$'
|
||||
echo "Process $$: Done making \$\$\$."
|
||||
|
||||
# "command options or path names"
|
||||
# ($1 is assumed to contain a value here)
|
||||
grep -li Hugo /dev/null "$1"
|
||||
|
||||
# Less simple examples
|
||||
# "quote variables, unless proven false": ccs might be empty
|
||||
git send-email --to "${reviewers}" ${ccs:+"--cc" "${ccs}"}
|
||||
|
||||
# Positional parameter precautions: $1 might be unset
|
||||
# Single quotes leave regex as-is.
|
||||
grep -cP '([Ss]pecial|\|?characters*)$' ${1:+"$1"}
|
||||
|
||||
# For passing on arguments,
|
||||
# "$@" is right almost every time, and
|
||||
# $* is wrong almost every time:
|
||||
#
|
||||
# * $* and $@ will split on spaces, clobbering up arguments
|
||||
# that contain spaces and dropping empty strings;
|
||||
# * "$@" will retain arguments as-is, so no args
|
||||
# provided will result in no args being passed on;
|
||||
# This is in most cases what you want to use for passing
|
||||
# on arguments.
|
||||
# * "$*" expands to one argument, with all args joined
|
||||
# by (usually) spaces,
|
||||
# so no args provided will result in one empty string
|
||||
# being passed on.
|
||||
#
|
||||
# Consult
|
||||
# https://www.gnu.org/software/bash/manual/html_node/Special-Parameters.html and
|
||||
# https://mywiki.wooledge.org/BashGuide/Arrays for more
|
||||
|
||||
(set -- 1 "2 two" "3 three tres"; echo $#; set -- "$*"; echo "$#, $@")
|
||||
(set -- 1 "2 two" "3 three tres"; echo $#; set -- "$@"; echo "$#, $@")
|
||||
|
||||
|
||||
Features and Bugs
|
||||
|
||||
ShellCheck
|
||||
|
||||
The ShellCheck project identifies common bugs and warnings for your shell scripts. It is recommended for all scripts, large or small.
|
||||
|
||||
Command Substitution
|
||||
|
||||
Use $(command) instead of backticks.
|
||||
|
||||
Nested backticks require escaping the inner ones with \ . The $(command) format doesn’t change when nested and is easier to read.
|
||||
|
||||
Example:
|
||||
|
||||
# This is preferred:
|
||||
var="$(command "$(command1)")"
|
||||
|
||||
# This is not:
|
||||
var="`command \`command1\``"
|
||||
|
||||
|
||||
Test, [ … ], and [[ … ]]
|
||||
|
||||
[[ … ]] is preferred over [ … ], test and /usr/bin/[.
|
||||
|
||||
[[ … ]] reduces errors as no pathname expansion or word splitting takes place between [[ and ]]. In addition, [[ … ]] allows for pattern and regular expression matching, while [ … ] does not.
|
||||
|
||||
# This ensures the string on the left is made up of characters in
|
||||
# the alnum character class followed by the string name.
|
||||
# Note that the RHS should not be quoted here.
|
||||
if [[ "filename" =~ ^[[:alnum:]]+name ]]; then
|
||||
echo "Match"
|
||||
fi
|
||||
|
||||
# This matches the exact pattern "f*" (Does not match in this case)
|
||||
if [[ "filename" == "f*" ]]; then
|
||||
echo "Match"
|
||||
fi
|
||||
|
||||
# This gives a "too many arguments" error as f* is expanded to the
|
||||
# contents of the current directory. It might also trigger the
|
||||
# "unexpected operator" error because `[` does not support `==`, only `=`.
|
||||
if [ "filename" == f* ]; then
|
||||
echo "Match"
|
||||
fi
|
||||
|
||||
|
||||
For the gory details, see E14 in the Bash FAQ
|
||||
|
||||
Testing Strings
|
||||
|
||||
Use quotes rather than filler characters where possible.
|
||||
|
||||
Bash is smart enough to deal with an empty string in a test. So, given that the code is much easier to read, use tests for empty/non-empty strings or empty strings rather than filler characters.
|
||||
|
||||
# Do this:
|
||||
if [[ "${my_var}" == "some_string" ]]; then
|
||||
do_something
|
||||
fi
|
||||
|
||||
# -z (string length is zero) and -n (string length is not zero) are
|
||||
# preferred over testing for an empty string
|
||||
if [[ -z "${my_var}" ]]; then
|
||||
do_something
|
||||
fi
|
||||
|
||||
# This is OK (ensure quotes on the empty side), but not preferred:
|
||||
if [[ "${my_var}" == "" ]]; then
|
||||
do_something
|
||||
fi
|
||||
|
||||
# Not this:
|
||||
if [[ "${my_var}X" == "some_stringX" ]]; then
|
||||
do_something
|
||||
fi
|
||||
|
||||
|
||||
To avoid confusion about what you’re testing for, explicitly use -z or -n.
|
||||
|
||||
# Use this
|
||||
if [[ -n "${my_var}" ]]; then
|
||||
do_something
|
||||
fi
|
||||
|
||||
# Instead of this
|
||||
if [[ "${my_var}" ]]; then
|
||||
do_something
|
||||
fi
|
||||
|
||||
|
||||
For clarity, use == for equality rather than = even though both work. The former encourages the use of [[ and the latter can be confused with an assignment. However, be careful when using < and > in [[ … ]] which performs a lexicographical comparison. Use (( … )) or -lt and -gt for numerical comparison.
|
||||
|
||||
# Use this
|
||||
if [[ "${my_var}" == "val" ]]; then
|
||||
do_something
|
||||
fi
|
||||
|
||||
if (( my_var > 3 )); then
|
||||
do_something
|
||||
fi
|
||||
|
||||
if [[ "${my_var}" -gt 3 ]]; then
|
||||
do_something
|
||||
fi
|
||||
|
||||
# Instead of this
|
||||
if [[ "${my_var}" = "val" ]]; then
|
||||
do_something
|
||||
fi
|
||||
|
||||
# Probably unintended lexicographical comparison.
|
||||
if [[ "${my_var}" > 3 ]]; then
|
||||
# True for 4, false for 22.
|
||||
do_something
|
||||
fi
|
||||
|
||||
|
||||
Wildcard Expansion of Filenames
|
||||
|
||||
Use an explicit path when doing wildcard expansion of filenames.
|
||||
|
||||
As filenames can begin with a -, it’s a lot safer to expand wildcards with ./* instead of *.
|
||||
|
||||
# Here's the contents of the directory:
|
||||
# -f -r somedir somefile
|
||||
|
||||
# Incorrectly deletes almost everything in the directory by force
|
||||
psa@bilby$ rm -v *
|
||||
removed directory: `somedir'
|
||||
removed `somefile'
|
||||
|
||||
# As opposed to:
|
||||
psa@bilby$ rm -v ./*
|
||||
removed `./-f'
|
||||
removed `./-r'
|
||||
rm: cannot remove `./somedir': Is a directory
|
||||
removed `./somefile'
|
||||
|
||||
|
||||
Eval
|
||||
|
||||
eval should be avoided.
|
||||
|
||||
Eval munges the input when used for assignment to variables and can set variables without making it possible to check what those variables were.
|
||||
|
||||
# What does this set?
|
||||
# Did it succeed? In part or whole?
|
||||
eval $(set_my_variables)
|
||||
|
||||
# What happens if one of the returned values has a space in it?
|
||||
variable="$(eval some_function)"
|
||||
|
||||
|
||||
Arrays
|
||||
|
||||
Bash arrays should be used to store lists of elements, to avoid quoting complications. This particularly applies to argument lists. Arrays should not be used to facilitate more complex data structures (see When to use Shell above).
|
||||
|
||||
Arrays store an ordered collection of strings, and can be safely expanded into individual elements for a command or loop.
|
||||
|
||||
Using a single string for multiple command arguments should be avoided, as it inevitably leads to authors using eval or trying to nest quotes inside the string, which does not give reliable or readable results and leads to needless complexity.
|
||||
|
||||
# An array is assigned using parentheses, and can be appended to
|
||||
# with +=( … ).
|
||||
declare -a flags
|
||||
flags=(--foo --bar='baz')
|
||||
flags+=(--greeting="Hello ${name}")
|
||||
mybinary "${flags[@]}"
|
||||
|
||||
# Don’t use strings for sequences.
|
||||
flags='--foo --bar=baz'
|
||||
flags+=' --greeting="Hello world"' # This won’t work as intended.
|
||||
mybinary ${flags}
|
||||
|
||||
# Command expansions return single strings, not arrays. Avoid
|
||||
# unquoted expansion in array assignments because it won’t
|
||||
# work correctly if the command output contains special
|
||||
# characters or whitespace.
|
||||
|
||||
# This expands the listing output into a string, then does special keyword
|
||||
# expansion, and then whitespace splitting. Only then is it turned into a
|
||||
# list of words. The ls command may also change behavior based on the user's
|
||||
# active environment!
|
||||
declare -a files=($(ls /directory))
|
||||
|
||||
# The get_arguments writes everything to STDOUT, but then goes through the
|
||||
# same expansion process above before turning into a list of arguments.
|
||||
mybinary $(get_arguments)
|
||||
|
||||
|
||||
Arrays Pros
|
||||
Using Arrays allows lists of things without confusing quoting semantics. Conversely, not using arrays leads to misguided attempts to nest quoting inside a string.
|
||||
Arrays make it possible to safely store sequences/lists of arbitrary strings, including strings containing whitespace.
|
||||
|
||||
Arrays Cons
|
||||
|
||||
Using arrays can risk a script’s complexity growing.
|
||||
|
||||
Arrays Decision
|
||||
|
||||
Arrays should be used to safely create and pass around lists. In particular, when building a set of command arguments, use arrays to avoid confusing quoting issues. Use quoted expansion – "${array[@]}" – to access arrays. However, if more advanced data manipulation is required, shell scripting should be avoided altogether; see above.
|
||||
|
||||
Pipes to While
|
||||
|
||||
Use process substitution or the readarray builtin (bash4+) in preference to piping to while. Pipes create a subshell, so any variables modified within a pipeline do not propagate to the parent shell.
|
||||
|
||||
The implicit subshell in a pipe to while can introduce subtle bugs that are hard to track down.
|
||||
|
||||
last_line='NULL'
|
||||
your_command | while read -r line; do
|
||||
if [[ -n "${line}" ]]; then
|
||||
last_line="${line}"
|
||||
fi
|
||||
done
|
||||
|
||||
# This will always output 'NULL'!
|
||||
echo "${last_line}"
|
||||
|
||||
|
||||
Using process substitution also creates a subshell. However, it allows redirecting from a subshell to a while without putting the while (or any other command) in a subshell.
|
||||
|
||||
last_line='NULL'
|
||||
while read line; do
|
||||
if [[ -n "${line}" ]]; then
|
||||
last_line="${line}"
|
||||
fi
|
||||
done < <(your_command)
|
||||
|
||||
# This will output the last non-empty line from your_command
|
||||
echo "${last_line}"
|
||||
|
||||
|
||||
Alternatively, use the readarray builtin to read the file into an array, then loop over the array’s contents. Notice that (for the same reason as above) you need to use a process substitution with readarray rather than a pipe, but with the advantage that the input generation for the loop is located before it, rather than after.
|
||||
|
||||
last_line='NULL'
|
||||
readarray -t lines < <(your_command)
|
||||
for line in "${lines[@]}"; do
|
||||
if [[ -n "${line}" ]]; then
|
||||
last_line="${line}"
|
||||
fi
|
||||
done
|
||||
echo "${last_line}"
|
||||
|
||||
|
||||
Note: Be cautious using a for-loop to iterate over output, as in for var in $(...), as the output is split by whitespace, not by line. Sometimes you will know this is safe because the output can’t contain any unexpected whitespace, but where this isn’t obvious or doesn’t improve readability (such as a long command inside $(...)), a while read loop or readarray is often safer and clearer.
|
||||
|
||||
Arithmetic
|
||||
|
||||
Always use (( … )) or $(( … )) rather than let or $[ … ] or expr.
|
||||
|
||||
Never use the $[ … ] syntax, the expr command, or the let built-in.
|
||||
|
||||
< and > don’t perform numerical comparison inside [[ … ]] expressions (they perform lexicographical comparisons instead; see Testing Strings). For preference, don’t use [[ … ]] at all for numeric comparisons, use (( … )) instead.
|
||||
|
||||
It is recommended to avoid using (( … )) as a standalone statement, and otherwise be wary of its expression evaluating to zero
|
||||
|
||||
particularly with set -e enabled. For example, set -e; i=0; (( i++ )) will cause the shell to exit.
|
||||
# Simple calculation used as text - note the use of $(( … )) within
|
||||
# a string.
|
||||
echo "$(( 2 + 2 )) is 4"
|
||||
|
||||
# When performing arithmetic comparisons for testing
|
||||
if (( a < b )); then
|
||||
…
|
||||
fi
|
||||
|
||||
# Some calculation assigned to a variable.
|
||||
(( i = 10 * j + 400 ))
|
||||
|
||||
# This form is non-portable and deprecated
|
||||
i=$[2 * 10]
|
||||
|
||||
# Despite appearances, 'let' isn't one of the declarative keywords,
|
||||
# so unquoted assignments are subject to globbing wordsplitting.
|
||||
# For the sake of simplicity, avoid 'let' and use (( … ))
|
||||
let i="2 + 2"
|
||||
|
||||
# The expr utility is an external program and not a shell builtin.
|
||||
i=$( expr 4 + 4 )
|
||||
|
||||
# Quoting can be error prone when using expr too.
|
||||
i=$( expr 4 '*' 4 )
|
||||
|
||||
|
||||
Stylistic considerations aside, the shell’s built-in arithmetic is many times faster than expr.
|
||||
|
||||
When using variables, the ${var} (and $var) forms are not required within $(( … )). The shell knows to look up var for you, and omitting the ${…} leads to cleaner code. This is slightly contrary to the previous rule about always using braces, so this is a recommendation only.
|
||||
|
||||
# N.B.: Remember to declare your variables as integers when
|
||||
# possible, and to prefer local variables over globals.
|
||||
local -i hundred="$(( 10 * 10 ))"
|
||||
declare -i five="$(( 10 / 2 ))"
|
||||
|
||||
# Increment the variable "i" by three.
|
||||
# Note that:
|
||||
# - We do not write ${i} or $i.
|
||||
# - We put a space after the (( and before the )).
|
||||
(( i += 3 ))
|
||||
|
||||
# To decrement the variable "i" by five:
|
||||
(( i -= 5 ))
|
||||
|
||||
# Do some complicated computations.
|
||||
# Note that normal arithmetic operator precedence is observed.
|
||||
hr=2
|
||||
min=5
|
||||
sec=30
|
||||
echo "$(( hr * 3600 + min * 60 + sec ))" # prints 7530 as expected
|
||||
|
||||
|
||||
Aliases
|
||||
|
||||
Although commonly seen in .bashrc files, aliases should be avoided in scripts. As the Bash manual notes:
|
||||
|
||||
For almost every purpose, shell functions are preferred over aliases.
|
||||
|
||||
Aliases are cumbersome to work with because they require carefully quoting and escaping their contents, and mistakes can be hard to notice.
|
||||
|
||||
# this evaluates $RANDOM once when the alias is defined,
|
||||
# so the echo'ed string will be the same on each invocation
|
||||
alias random_name="echo some_prefix_${RANDOM}"
|
||||
|
||||
|
||||
Functions provide a superset of alias’ functionality and should always be preferred. .
|
||||
|
||||
random_name() {
|
||||
echo "some_prefix_${RANDOM}"
|
||||
}
|
||||
|
||||
# Note that unlike aliases function's arguments are accessed via $@
|
||||
fancy_ls() {
|
||||
ls -lh "$@"
|
||||
}
|
||||
|
||||
|
||||
Naming Conventions
|
||||
|
||||
Function Names
|
||||
|
||||
Lower-case, with underscores to separate words. Separate libraries with ::. Parentheses are required after the function name. The keyword function is optional, but must be used consistently throughout a project.
|
||||
|
||||
If you’re writing single functions, use lowercase and separate words with underscore. If you’re writing a package, separate package names with ::. However, functions intended for interactive use may choose to avoid colons as it can confuse bash auto-completion.
|
||||
|
||||
Braces must be on the same line as the function name (as with other languages at Google) and no space between the function name and the parenthesis.
|
||||
|
||||
# Single function
|
||||
my_func() {
|
||||
…
|
||||
}
|
||||
|
||||
# Part of a package
|
||||
mypackage::my_func() {
|
||||
…
|
||||
}
|
||||
|
||||
|
||||
The function keyword is extraneous when “()” is present after the function name, but enhances quick identification of functions.
|
||||
|
||||
Variable Names
|
||||
|
||||
Same as for function names.
|
||||
|
||||
Variables names for loops should be similarly named for any variable you’re looping through.
|
||||
|
||||
for zone in "${zones[@]}"; do
|
||||
something_with "${zone}"
|
||||
done
|
||||
|
||||
|
||||
Constants, Environment Variables, and readonly Variables
|
||||
|
||||
Constants and anything exported to the environment should be capitalized, separated with underscores, and declared at the top of the file.
|
||||
|
||||
# Constant
|
||||
readonly PATH_TO_FILES='/some/path'
|
||||
|
||||
# Both constant and exported to the environment
|
||||
declare -xr ORACLE_SID='PROD'
|
||||
|
||||
|
||||
For the sake of clarity readonly or export is recommended vs. the equivalent declare commands. You can do one after the other, like:
|
||||
|
||||
# Constant
|
||||
readonly PATH_TO_FILES='/some/path'
|
||||
export PATH_TO_FILES
|
||||
|
||||
|
||||
It’s OK to set a constant at runtime or in a conditional, but it should be made readonly immediately afterwards.
|
||||
|
||||
ZIP_VERSION="$(dpkg --status zip | sed -n 's/^Version: //p')"
|
||||
if [[ -z "${ZIP_VERSION}" ]]; then
|
||||
ZIP_VERSION="$(pacman -Q --info zip | sed -n 's/^Version *: //p')"
|
||||
fi
|
||||
if [[ -z "${ZIP_VERSION}" ]]; then
|
||||
handle_error_and_quit
|
||||
fi
|
||||
readonly ZIP_VERSION
|
||||
|
||||
|
||||
Source Filenames
|
||||
|
||||
Lowercase, with underscores to separate words if desired.
|
||||
|
||||
This is for consistency with other code styles in Google: maketemplate or make_template but not make-template.
|
||||
|
||||
Use Local Variables
|
||||
|
||||
Declare function-specific variables with local.
|
||||
|
||||
Ensure that local variables are only seen inside a function and its children by using local when declaring them. This avoids polluting the global namespace and inadvertently setting variables that may have significance outside the function.
|
||||
|
||||
Declaration and assignment must be separate statements when the assignment value is provided by a command substitution; as the local builtin does not propagate the exit code from the command substitution.
|
||||
|
||||
my_func2() {
|
||||
local name="$1"
|
||||
|
||||
# Separate lines for declaration and assignment:
|
||||
local my_var
|
||||
my_var="$(my_func)"
|
||||
(( $? == 0 )) || return
|
||||
|
||||
…
|
||||
}
|
||||
|
||||
my_func2() {
|
||||
# DO NOT do this:
|
||||
# $? will always be zero, as it contains the exit code of 'local', not my_func
|
||||
local my_var="$(my_func)"
|
||||
(( $? == 0 )) || return
|
||||
|
||||
…
|
||||
}
|
||||
|
||||
|
||||
Function Location
|
||||
|
||||
Put all functions together in the file just below constants. Don’t hide executable code between functions. Doing so makes the code difficult to follow and results in nasty surprises when debugging.
|
||||
|
||||
If you’ve got functions, put them all together near the top of the file. Only includes, set statements and setting constants may be done before declaring functions.
|
||||
|
||||
main
|
||||
|
||||
A function called main is required for scripts long enough to contain at least one other function.
|
||||
|
||||
In order to easily find the start of the program, put the main program in a function called main as the bottom-most function. This provides consistency with the rest of the code base as well as allowing you to define more variables as local (which can’t be done if the main code is not a function). The last non-comment line in the file should be a call to main:
|
||||
|
||||
main "$@"
|
||||
|
||||
|
||||
Obviously, for short scripts where it’s just a linear flow, main is overkill and so is not required.
|
||||
|
||||
Calling Commands
|
||||
|
||||
Checking Return Values
|
||||
|
||||
Always check return values and give informative return values.
|
||||
|
||||
For unpiped commands, use $? or check directly via an if statement to keep it simple.
|
||||
|
||||
Example:
|
||||
|
||||
if ! mv "${file_list[@]}" "${dest_dir}/"; then
|
||||
echo "Unable to move ${file_list[*]} to ${dest_dir}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Or
|
||||
mv "${file_list[@]}" "${dest_dir}/"
|
||||
if (( $? != 0 )); then
|
||||
echo "Unable to move ${file_list[*]} to ${dest_dir}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
Bash also has the PIPESTATUS variable that allows checking of the return code from all parts of a pipe. If it’s only necessary to check success or failure of the whole pipe, then the following is acceptable:
|
||||
|
||||
tar -cf - ./* | ( cd "${dir}" && tar -xf - )
|
||||
if (( PIPESTATUS[0] != 0 || PIPESTATUS[1] != 0 )); then
|
||||
echo "Unable to tar files to ${dir}" >&2
|
||||
fi
|
||||
|
||||
|
||||
However, as PIPESTATUS will be overwritten as soon as you do any other command, if you need to act differently on errors based on where it happened in the pipe, you’ll need to assign PIPESTATUS to another variable immediately after running the command (don’t forget that [ is a command and will wipe out PIPESTATUS).
|
||||
|
||||
tar -cf - ./* | ( cd "${DIR}" && tar -xf - )
|
||||
return_codes=( "${PIPESTATUS[@]}" )
|
||||
if (( return_codes[0] != 0 )); then
|
||||
do_something
|
||||
fi
|
||||
if (( return_codes[1] != 0 )); then
|
||||
do_something_else
|
||||
fi
|
||||
|
||||
|
||||
Builtin Commands vs. External Commands
|
||||
|
||||
Given the choice between invoking a shell builtin and invoking a separate process, choose the builtin.
|
||||
|
||||
We prefer the use of builtins such as the Parameter Expansion functionality provided by bash as it’s more efficient, robust, and portable (especially when compared to things like sed). See also the =~ operator.
|
||||
|
||||
Examples:
|
||||
|
||||
# Prefer this:
|
||||
addition="$(( X + Y ))"
|
||||
substitution="${string/#foo/bar}"
|
||||
if [[ "${string}" =~ foo:(\d+) ]]; then
|
||||
extraction="${BASH_REMATCH[1]}"
|
||||
fi
|
||||
|
||||
# Instead of this:
|
||||
addition="$(expr "${X}" + "${Y}")"
|
||||
substitution="$(echo "${string}" | sed -e 's/^foo/bar/')"
|
||||
extraction="$(echo "${string}" | sed -e 's/foo:\([0-9]\)/\1/')"
|
||||
|
||||
|
||||
When in Doubt: Be Consistent
|
||||
|
||||
Using one style consistently through our codebase lets us focus on other (more important) issues. Consistency also allows for automation. In many cases, rules that are attributed to “Be Consistent” boil down to “Just pick one and stop worrying about it”; the potential value of allowing flexibility on these points is outweighed by the cost of having people argue over them.
|
||||
|
||||
However, there are limits to consistency. It is a good tie breaker when there is no clear technical argument, nor a long-term direction. Consistency should not generally be used as a justification to do things in an old style without considering the benefits of the new style, or the tendency of the codebase to converge on newer styles over time.
|
||||
109
ai/skills/tdd/SKILL.md
Normal file
109
ai/skills/tdd/SKILL.md
Normal file
@@ -0,0 +1,109 @@
|
||||
---
|
||||
name: tdd
|
||||
description: Test-driven development with red-green-refactor loop. Use when user wants to build features or fix bugs using TDD, mentions "red-green-refactor", wants integration tests, or asks for test-first development.
|
||||
---
|
||||
|
||||
# Test-Driven Development
|
||||
|
||||
## Philosophy
|
||||
|
||||
**Core principle**: Tests should verify behavior through public interfaces, not implementation details. Code can change entirely; tests shouldn't.
|
||||
|
||||
**Good tests** are integration-style: they exercise real code paths through public APIs. They describe _what_ the system does, not _how_ it does it. A good test reads like a specification - "user can checkout with valid cart" tells you exactly what capability exists. These tests survive refactors because they don't care about internal structure.
|
||||
|
||||
**Bad tests** are coupled to implementation. They mock internal collaborators, test private methods, or verify through external means (like querying a database directly instead of using the interface). The warning sign: your test breaks when you refactor, but behavior hasn't changed. If you rename an internal function and tests fail, those tests were testing implementation, not behavior.
|
||||
|
||||
See [tests.md](tests.md) for examples and [mocking.md](mocking.md) for mocking guidelines.
|
||||
|
||||
## Anti-Pattern: Horizontal Slices
|
||||
|
||||
**DO NOT write all tests first, then all implementation.** This is "horizontal slicing" - treating RED as "write all tests" and GREEN as "write all code."
|
||||
|
||||
This produces **crap tests**:
|
||||
|
||||
- Tests written in bulk test _imagined_ behavior, not _actual_ behavior
|
||||
- You end up testing the _shape_ of things (data structures, function signatures) rather than user-facing behavior
|
||||
- Tests become insensitive to real changes - they pass when behavior breaks, fail when behavior is fine
|
||||
- You outrun your headlights, committing to test structure before understanding the implementation
|
||||
|
||||
**Correct approach**: Vertical slices via tracer bullets. One test → one implementation → repeat. Each test responds to what you learned from the previous cycle. Because you just wrote the code, you know exactly what behavior matters and how to verify it.
|
||||
|
||||
```
|
||||
WRONG (horizontal):
|
||||
RED: test1, test2, test3, test4, test5
|
||||
GREEN: impl1, impl2, impl3, impl4, impl5
|
||||
|
||||
RIGHT (vertical):
|
||||
RED→GREEN: test1→impl1
|
||||
RED→GREEN: test2→impl2
|
||||
RED→GREEN: test3→impl3
|
||||
...
|
||||
```
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Planning
|
||||
|
||||
When exploring the codebase, use the project's domain glossary so that test names and interface vocabulary match the project's language, and respect ADRs in the area you're touching.
|
||||
|
||||
Before writing any code:
|
||||
|
||||
- [ ] Confirm with user what interface changes are needed
|
||||
- [ ] Confirm with user which behaviors to test (prioritize)
|
||||
- [ ] Identify opportunities for [deep modules](deep-modules.md) (small interface, deep implementation)
|
||||
- [ ] Design interfaces for [testability](interface-design.md)
|
||||
- [ ] List the behaviors to test (not implementation steps)
|
||||
- [ ] Get user approval on the plan
|
||||
|
||||
Ask: "What should the public interface look like? Which behaviors are most important to test?"
|
||||
|
||||
**You can't test everything.** Confirm with the user exactly which behaviors matter most. Focus testing effort on critical paths and complex logic, not every possible edge case.
|
||||
|
||||
### 2. Tracer Bullet
|
||||
|
||||
Write ONE test that confirms ONE thing about the system:
|
||||
|
||||
```
|
||||
RED: Write test for first behavior → test fails
|
||||
GREEN: Write minimal code to pass → test passes
|
||||
```
|
||||
|
||||
This is your tracer bullet - proves the path works end-to-end.
|
||||
|
||||
### 3. Incremental Loop
|
||||
|
||||
For each remaining behavior:
|
||||
|
||||
```
|
||||
RED: Write next test → fails
|
||||
GREEN: Minimal code to pass → passes
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
- One test at a time
|
||||
- Only enough code to pass current test
|
||||
- Don't anticipate future tests
|
||||
- Keep tests focused on observable behavior
|
||||
|
||||
### 4. Refactor
|
||||
|
||||
After all tests pass, look for [refactor candidates](refactoring.md):
|
||||
|
||||
- [ ] Extract duplication
|
||||
- [ ] Deepen modules (move complexity behind simple interfaces)
|
||||
- [ ] Apply SOLID principles where natural
|
||||
- [ ] Consider what new code reveals about existing code
|
||||
- [ ] Run tests after each refactor step
|
||||
|
||||
**Never refactor while RED.** Get to GREEN first.
|
||||
|
||||
## Checklist Per Cycle
|
||||
|
||||
```
|
||||
[ ] Test describes behavior, not implementation
|
||||
[ ] Test uses public interface only
|
||||
[ ] Test would survive internal refactor
|
||||
[ ] Code is minimal for this test
|
||||
[ ] No speculative features added
|
||||
```
|
||||
33
ai/skills/tdd/deep-modules.md
Normal file
33
ai/skills/tdd/deep-modules.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Deep Modules
|
||||
|
||||
From "A Philosophy of Software Design":
|
||||
|
||||
**Deep module** = small interface + lots of implementation
|
||||
|
||||
```
|
||||
┌─────────────────────┐
|
||||
│ Small Interface │ ← Few methods, simple params
|
||||
├─────────────────────┤
|
||||
│ │
|
||||
│ │
|
||||
│ Deep Implementation│ ← Complex logic hidden
|
||||
│ │
|
||||
│ │
|
||||
└─────────────────────┘
|
||||
```
|
||||
|
||||
**Shallow module** = large interface + little implementation (avoid)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────┐
|
||||
│ Large Interface │ ← Many methods, complex params
|
||||
├─────────────────────────────────┤
|
||||
│ Thin Implementation │ ← Just passes through
|
||||
└─────────────────────────────────┘
|
||||
```
|
||||
|
||||
When designing interfaces, ask:
|
||||
|
||||
- Can I reduce the number of methods?
|
||||
- Can I simplify the parameters?
|
||||
- Can I hide more complexity inside?
|
||||
31
ai/skills/tdd/interface-design.md
Normal file
31
ai/skills/tdd/interface-design.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Interface Design for Testability
|
||||
|
||||
Good interfaces make testing natural:
|
||||
|
||||
1. **Accept dependencies, don't create them**
|
||||
|
||||
```typescript
|
||||
// Testable
|
||||
function processOrder(order, paymentGateway) {}
|
||||
|
||||
// Hard to test
|
||||
function processOrder(order) {
|
||||
const gateway = new StripeGateway();
|
||||
}
|
||||
```
|
||||
|
||||
2. **Return results, don't produce side effects**
|
||||
|
||||
```typescript
|
||||
// Testable
|
||||
function calculateDiscount(cart): Discount {}
|
||||
|
||||
// Hard to test
|
||||
function applyDiscount(cart): void {
|
||||
cart.total -= discount;
|
||||
}
|
||||
```
|
||||
|
||||
3. **Small surface area**
|
||||
- Fewer methods = fewer tests needed
|
||||
- Fewer params = simpler test setup
|
||||
59
ai/skills/tdd/mocking.md
Normal file
59
ai/skills/tdd/mocking.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# When to Mock
|
||||
|
||||
Mock at **system boundaries** only:
|
||||
|
||||
- External APIs (payment, email, etc.)
|
||||
- Databases (sometimes - prefer test DB)
|
||||
- Time/randomness
|
||||
- File system (sometimes)
|
||||
|
||||
Don't mock:
|
||||
|
||||
- Your own classes/modules
|
||||
- Internal collaborators
|
||||
- Anything you control
|
||||
|
||||
## Designing for Mockability
|
||||
|
||||
At system boundaries, design interfaces that are easy to mock:
|
||||
|
||||
**1. Use dependency injection**
|
||||
|
||||
Pass external dependencies in rather than creating them internally:
|
||||
|
||||
```typescript
|
||||
// Easy to mock
|
||||
function processPayment(order, paymentClient) {
|
||||
return paymentClient.charge(order.total);
|
||||
}
|
||||
|
||||
// Hard to mock
|
||||
function processPayment(order) {
|
||||
const client = new StripeClient(process.env.STRIPE_KEY);
|
||||
return client.charge(order.total);
|
||||
}
|
||||
```
|
||||
|
||||
**2. Prefer SDK-style interfaces over generic fetchers**
|
||||
|
||||
Create specific functions for each external operation instead of one generic function with conditional logic:
|
||||
|
||||
```typescript
|
||||
// GOOD: Each function is independently mockable
|
||||
const api = {
|
||||
getUser: (id) => fetch(`/users/${id}`),
|
||||
getOrders: (userId) => fetch(`/users/${userId}/orders`),
|
||||
createOrder: (data) => fetch('/orders', { method: 'POST', body: data }),
|
||||
};
|
||||
|
||||
// BAD: Mocking requires conditional logic inside the mock
|
||||
const api = {
|
||||
fetch: (endpoint, options) => fetch(endpoint, options),
|
||||
};
|
||||
```
|
||||
|
||||
The SDK approach means:
|
||||
- Each mock returns one specific shape
|
||||
- No conditional logic in test setup
|
||||
- Easier to see which endpoints a test exercises
|
||||
- Type safety per endpoint
|
||||
10
ai/skills/tdd/refactoring.md
Normal file
10
ai/skills/tdd/refactoring.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# Refactor Candidates
|
||||
|
||||
After TDD cycle, look for:
|
||||
|
||||
- **Duplication** → Extract function/class
|
||||
- **Long methods** → Break into private helpers (keep tests on public interface)
|
||||
- **Shallow modules** → Combine or deepen
|
||||
- **Feature envy** → Move logic to where data lives
|
||||
- **Primitive obsession** → Introduce value objects
|
||||
- **Existing code** the new code reveals as problematic
|
||||
61
ai/skills/tdd/tests.md
Normal file
61
ai/skills/tdd/tests.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# Good and Bad Tests
|
||||
|
||||
## Good Tests
|
||||
|
||||
**Integration-style**: Test through real interfaces, not mocks of internal parts.
|
||||
|
||||
```typescript
|
||||
// GOOD: Tests observable behavior
|
||||
test("user can checkout with valid cart", async () => {
|
||||
const cart = createCart();
|
||||
cart.add(product);
|
||||
const result = await checkout(cart, paymentMethod);
|
||||
expect(result.status).toBe("confirmed");
|
||||
});
|
||||
```
|
||||
|
||||
Characteristics:
|
||||
|
||||
- Tests behavior users/callers care about
|
||||
- Uses public API only
|
||||
- Survives internal refactors
|
||||
- Describes WHAT, not HOW
|
||||
- One logical assertion per test
|
||||
|
||||
## Bad Tests
|
||||
|
||||
**Implementation-detail tests**: Coupled to internal structure.
|
||||
|
||||
```typescript
|
||||
// BAD: Tests implementation details
|
||||
test("checkout calls paymentService.process", async () => {
|
||||
const mockPayment = jest.mock(paymentService);
|
||||
await checkout(cart, payment);
|
||||
expect(mockPayment.process).toHaveBeenCalledWith(cart.total);
|
||||
});
|
||||
```
|
||||
|
||||
Red flags:
|
||||
|
||||
- Mocking internal collaborators
|
||||
- Testing private methods
|
||||
- Asserting on call counts/order
|
||||
- Test breaks when refactoring without behavior change
|
||||
- Test name describes HOW not WHAT
|
||||
- Verifying through external means instead of interface
|
||||
|
||||
```typescript
|
||||
// BAD: Bypasses interface to verify
|
||||
test("createUser saves to database", async () => {
|
||||
await createUser({ name: "Alice" });
|
||||
const row = await db.query("SELECT * FROM users WHERE name = ?", ["Alice"]);
|
||||
expect(row).toBeDefined();
|
||||
});
|
||||
|
||||
// GOOD: Verifies through interface
|
||||
test("createUser makes user retrievable", async () => {
|
||||
const user = await createUser({ name: "Alice" });
|
||||
const retrieved = await getUser(user.id);
|
||||
expect(retrieved.name).toBe("Alice");
|
||||
});
|
||||
```
|
||||
76
ai/skills/to-prd/SKILL.md
Normal file
76
ai/skills/to-prd/SKILL.md
Normal file
@@ -0,0 +1,76 @@
|
||||
---
|
||||
name: to-prd
|
||||
description: Turn the current conversation context into a PRD and publish it to the project issue tracker. Use when user wants to create a PRD from the current context.
|
||||
---
|
||||
|
||||
This skill takes the current conversation context and codebase understanding and produces a PRD. Do NOT interview the user — just synthesize what you already know.
|
||||
|
||||
The issue tracker and triage label vocabulary should have been provided to you — run `/setup-matt-pocock-skills` if not.
|
||||
|
||||
## Process
|
||||
|
||||
1. Explore the repo to understand the current state of the codebase, if you haven't already. Use the project's domain glossary vocabulary throughout the PRD, and respect any ADRs in the area you're touching.
|
||||
|
||||
2. Sketch out the major modules you will need to build or modify to complete the implementation. Actively look for opportunities to extract deep modules that can be tested in isolation.
|
||||
|
||||
A deep module (as opposed to a shallow module) is one which encapsulates a lot of functionality in a simple, testable interface which rarely changes.
|
||||
|
||||
Check with the user that these modules match their expectations. Check with the user which modules they want tests written for.
|
||||
|
||||
3. Write the PRD using the template below, then publish it to the project issue tracker. Apply the `ready-for-agent` triage label - no need for additional triage.
|
||||
|
||||
<prd-template>
|
||||
|
||||
## Problem Statement
|
||||
|
||||
The problem that the user is facing, from the user's perspective.
|
||||
|
||||
## Solution
|
||||
|
||||
The solution to the problem, from the user's perspective.
|
||||
|
||||
## User Stories
|
||||
|
||||
A LONG, numbered list of user stories. Each user story should be in the format of:
|
||||
|
||||
1. As an <actor>, I want a <feature>, so that <benefit>
|
||||
|
||||
<user-story-example>
|
||||
1. As a mobile bank customer, I want to see balance on my accounts, so that I can make better informed decisions about my spending
|
||||
</user-story-example>
|
||||
|
||||
This list of user stories should be extremely extensive and cover all aspects of the feature.
|
||||
|
||||
## Implementation Decisions
|
||||
|
||||
A list of implementation decisions that were made. This can include:
|
||||
|
||||
- The modules that will be built/modified
|
||||
- The interfaces of those modules that will be modified
|
||||
- Technical clarifications from the developer
|
||||
- Architectural decisions
|
||||
- Schema changes
|
||||
- API contracts
|
||||
- Specific interactions
|
||||
|
||||
Do NOT include specific file paths or code snippets. They may end up being outdated very quickly.
|
||||
|
||||
Exception: if a prototype produced a snippet that encodes a decision more precisely than prose can (state machine, reducer, schema, type shape), inline it within the relevant decision and note briefly that it came from a prototype. Trim to the decision-rich parts — not a working demo, just the important bits.
|
||||
|
||||
## Testing Decisions
|
||||
|
||||
A list of testing decisions that were made. Include:
|
||||
|
||||
- A description of what makes a good test (only test external behavior, not implementation details)
|
||||
- Which modules will be tested
|
||||
- Prior art for the tests (i.e. similar types of tests in the codebase)
|
||||
|
||||
## Out of Scope
|
||||
|
||||
A description of the things that are out of scope for this PRD.
|
||||
|
||||
## Further Notes
|
||||
|
||||
Any further notes about the feature.
|
||||
|
||||
</prd-template>
|
||||
34
ai/skills/web-to-markdown/SKILL.md
Normal file
34
ai/skills/web-to-markdown/SKILL.md
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
name: web-to-markdown
|
||||
description: "Use when the user asks to grab, download, or copy an article from a website (e.g. 'grab me a copy of <url>' or 'convert <url> to markdown'). This skill uses the web-to-markdown utility to convert articles to markdown and download inline images."
|
||||
---
|
||||
|
||||
# Web-to-Markdown Skill
|
||||
|
||||
This skill allows the agent to download an HTML page, extract its main article content, convert it to Markdown, and download all inline images using the local `web-to-markdown` utility.
|
||||
|
||||
## Prerequisites
|
||||
- The utility is located at `/srv/dev/web-to-markdown/web-to-markdown`.
|
||||
- Always check that this executable exists before proceeding.
|
||||
|
||||
## Workflow
|
||||
|
||||
When the user asks to download or grab a copy of a website article, follow these steps:
|
||||
|
||||
1. **Ask for configuration:**
|
||||
Before running the script, ask the user:
|
||||
- **Destination:** Where should the article be saved? (Suggest the current directory or a logical default like `docs/` or `notes/`).
|
||||
- **Title:** What should the folder/article title be? (Suggest a simplified version of the URL slug or ask if they want the tool to extract the default title by omitting the title flag).
|
||||
|
||||
2. **Execute the Utility:**
|
||||
Once you have the configuration, use the `run_shell_command` tool to execute the `web-to-markdown` utility.
|
||||
|
||||
**Command Syntax:**
|
||||
` /srv/dev/web-to-markdown/web-to-markdown -out "<destination_path>" -title "<custom_title>" "<url>" `
|
||||
*Note: Omit `-title "<custom_title>"` if the user wants the tool to use the default parsed title.*
|
||||
|
||||
3. **Verify and Confirm:**
|
||||
- Review the output of the shell command to ensure it was successful.
|
||||
- List the target directory to verify the `index.md` and any downloaded images exist.
|
||||
- Inform the user of the successful download and the exact path where the new markdown file is located.
|
||||
|
||||
25
ai/skills/workflow_management/SKILL.md
Normal file
25
ai/skills/workflow_management/SKILL.md
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
name: workflow-management
|
||||
description: Specialized skill for creating, updating, and validating workflow documents in the Gemini Workflow Framework.
|
||||
---
|
||||
|
||||
# Workflow Management Skill
|
||||
|
||||
This skill allows Gemini to efficiently manage the lifecycle of project workflows.
|
||||
|
||||
## Functions
|
||||
|
||||
1. **Workflow Creation**: Propose new workflows using the standardized format (Objective, Action Items, Verification).
|
||||
2. **Step Mapping**: Automatically map high-level project goals to discrete, verifiable workflow steps.
|
||||
3. **Public Audit**: For each step, identify and link to the relevant public documentation (e.g., GitHub, MDN, public API docs).
|
||||
4. **Consistency Check**: Ensure that all action items align with the "Public Constraint Protocol" in `GEMINI.md`.
|
||||
|
||||
## Standard Workflow Format
|
||||
|
||||
### Workflow: [Name]
|
||||
|
||||
#### Step [X]: [Objective Summary]
|
||||
- **Goal**: [Detailed goal]
|
||||
- **Action Items**:
|
||||
- [ ] [Specific task]
|
||||
- **Verification**: [Public-domain method to verify success]
|
||||
117
ai/skills/write-a-skill/SKILL.md
Normal file
117
ai/skills/write-a-skill/SKILL.md
Normal file
@@ -0,0 +1,117 @@
|
||||
---
|
||||
name: write-a-skill
|
||||
description: Create new agent skills with proper structure, progressive disclosure, and bundled resources. Use when user wants to create, write, or build a new skill.
|
||||
---
|
||||
|
||||
# Writing Skills
|
||||
|
||||
## Process
|
||||
|
||||
1. **Gather requirements** - ask user about:
|
||||
- What task/domain does the skill cover?
|
||||
- What specific use cases should it handle?
|
||||
- Does it need executable scripts or just instructions?
|
||||
- Any reference materials to include?
|
||||
|
||||
2. **Draft the skill** - create:
|
||||
- SKILL.md with concise instructions
|
||||
- Additional reference files if content exceeds 500 lines
|
||||
- Utility scripts if deterministic operations needed
|
||||
|
||||
3. **Review with user** - present draft and ask:
|
||||
- Does this cover your use cases?
|
||||
- Anything missing or unclear?
|
||||
- Should any section be more/less detailed?
|
||||
|
||||
## Skill Structure
|
||||
|
||||
```
|
||||
skill-name/
|
||||
├── SKILL.md # Main instructions (required)
|
||||
├── REFERENCE.md # Detailed docs (if needed)
|
||||
├── EXAMPLES.md # Usage examples (if needed)
|
||||
└── scripts/ # Utility scripts (if needed)
|
||||
└── helper.js
|
||||
```
|
||||
|
||||
## SKILL.md Template
|
||||
|
||||
```md
|
||||
---
|
||||
name: skill-name
|
||||
description: Brief description of capability. Use when [specific triggers].
|
||||
---
|
||||
|
||||
# Skill Name
|
||||
|
||||
## Quick start
|
||||
|
||||
[Minimal working example]
|
||||
|
||||
## Workflows
|
||||
|
||||
[Step-by-step processes with checklists for complex tasks]
|
||||
|
||||
## Advanced features
|
||||
|
||||
[Link to separate files: See [REFERENCE.md](REFERENCE.md)]
|
||||
```
|
||||
|
||||
## Description Requirements
|
||||
|
||||
The description is **the only thing your agent sees** when deciding which skill to load. It's surfaced in the system prompt alongside all other installed skills. Your agent reads these descriptions and picks the relevant skill based on the user's request.
|
||||
|
||||
**Goal**: Give your agent just enough info to know:
|
||||
|
||||
1. What capability this skill provides
|
||||
2. When/why to trigger it (specific keywords, contexts, file types)
|
||||
|
||||
**Format**:
|
||||
|
||||
- Max 1024 chars
|
||||
- Write in third person
|
||||
- First sentence: what it does
|
||||
- Second sentence: "Use when [specific triggers]"
|
||||
|
||||
**Good example**:
|
||||
|
||||
```
|
||||
Extract text and tables from PDF files, fill forms, merge documents. Use when working with PDF files or when user mentions PDFs, forms, or document extraction.
|
||||
```
|
||||
|
||||
**Bad example**:
|
||||
|
||||
```
|
||||
Helps with documents.
|
||||
```
|
||||
|
||||
The bad example gives your agent no way to distinguish this from other document skills.
|
||||
|
||||
## When to Add Scripts
|
||||
|
||||
Add utility scripts when:
|
||||
|
||||
- Operation is deterministic (validation, formatting)
|
||||
- Same code would be generated repeatedly
|
||||
- Errors need explicit handling
|
||||
|
||||
Scripts save tokens and improve reliability vs generated code.
|
||||
|
||||
## When to Split Files
|
||||
|
||||
Split into separate files when:
|
||||
|
||||
- SKILL.md exceeds 100 lines
|
||||
- Content has distinct domains (finance vs sales schemas)
|
||||
- Advanced features are rarely needed
|
||||
|
||||
## Review Checklist
|
||||
|
||||
After drafting, verify:
|
||||
|
||||
- [ ] Description includes triggers ("Use when...")
|
||||
- [ ] SKILL.md under 100 lines
|
||||
- [ ] No time-sensitive info
|
||||
- [ ] Consistent terminology
|
||||
- [ ] Concrete examples included
|
||||
- [ ] References one level deep
|
||||
Reference in New Issue
Block a user