diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index bed7d1a..0000000 --- a/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -examples/embedder_static/* linguist-generated -examples/typescript/generated.ts linguist-generated diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml deleted file mode 100644 index 888c5ed..0000000 --- a/.github/workflows/check.yaml +++ /dev/null @@ -1,28 +0,0 @@ -name: check - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - check: - runs-on: ubuntu-latest - - strategy: - matrix: - deno-version: [vx.x.x] - - steps: - - uses: actions/checkout@v2 - - - uses: denoland/setup-deno@v1 - with: - deno-version: ${{ matrix.deno-version }} - - - name: Check - run: | - deno task generate - deno task all - git diff --exit-code diff --git a/.github/workflows/deno-test.yml b/.github/workflows/deno-test.yml new file mode 100644 index 0000000..8749234 --- /dev/null +++ b/.github/workflows/deno-test.yml @@ -0,0 +1,27 @@ +name: deno test +on: + push: + branches: "main" + paths-ignore: + - .gitignore + - README.md + - LICENSE + - .github/** + - "!.github/workflows/deno-test.yml" + pull_request: + paths-ignore: + - .gitignore + - README.md + - LICENSE + - .github/** + - "!.github/workflows/deno-test.yml" +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +jobs: + deno-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: denoland/setup-deno@v1 + - run: deno test -A diff --git a/.vscode/settings.json b/.vscode/settings.json index 353e5f5..f8878e7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,12 @@ { "deno.enable": true, - "deno.config": "./deno.jsonc", - "editor.formatOnSave": true, - "editor.defaultFormatter": "denoland.vscode-deno" + "deno.lint": true, + "editor.defaultFormatter": "denoland.vscode-deno", + "[typescript]": { "editor.defaultFormatter": "denoland.vscode-deno" }, + "[typescriptreact]": { "editor.defaultFormatter": "denoland.vscode-deno" }, + "[javascript]": { "editor.defaultFormatter": "denoland.vscode-deno" }, + "[javascriptreact]": { "editor.defaultFormatter": "denoland.vscode-deno" }, + "[json]": { "editor.defaultFormatter": "denoland.vscode-deno" }, + "[jsonc]": { "editor.defaultFormatter": "denoland.vscode-deno" }, + "[markdown]": { "editor.defaultFormatter": "denoland.vscode-deno" } } diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index df7b89e..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,107 +0,0 @@ -# Contributing - -Thank you for considering contributing to the `deno_generate` repository. We -appreciate your interest and efforts in making this project better. This -document will guide you on how to contribute effectively. - -## Project - -The `deno_generate` repository is part of the Deno ecosystem -() but is not an official Deno project at this -time. It aims to provide a code generation tool for Deno projects. - -## Getting Started - -To get started with contributing to `deno_generate`, follow these steps: - -1. Read the - [contribution guidelines](https://deno.com/manual/references/contributing) - for Deno. Although this project is not an official Deno project, the - contribution guidelines provide valuable information on how to contribute - effectively. - -2. Fork the `deno_generate` repository to your GitHub account. - -3. Clone the forked repository to your local machine. - -4. Make the necessary changes or additions to the codebase. - -5. Ensure that your changes adhere to the style guide provided in the - repository. - -6. Write descriptive commit messages for your changes. - -7. Push your changes to your forked repository. - -8. Submit a pull request (PR) to the `deno_generate` repository, describing the - changes you have made. - -## General Guidelines - -Here are some general guidelines to keep in mind while contributing to -`deno_generate`: - -- Maintain a professional and respectful attitude in all interactions related to - this project. Refer to the - [Rust's code of conduct](https://www.rust-lang.org/policies/code-of-conduct) - for guidance. - -- If you encounter any issues or need help, feel free to ask for assistance in - the [community chat room](https://discord.gg/deno). - -- Before working on an existing issue, comment on the issue to let others know - that you are going to work on it. - -- For new features, create an issue first and discuss it with other - contributors. This step ensures that your proposed feature aligns with the - project's goals and increases the chances of its acceptance. - -## Submitting a Pull Request - -When submitting a pull request, ensure that you follow these guidelines: - -1. Give your pull request a descriptive title summarizing the changes you have - made. - - Good examples: - - feat: Add new code generation feature - - fix: Resolve issue with code formatting - - Bad examples: - - fix #123 - - update code - -2. Reference the related issue(s) in the pull request description. - -3. Include tests that cover the changes you have made. Tests help ensure the - stability and quality of the project. - -## Additional Guidelines - -If you are submitting a pull request specifically for the `deno_generate` -repository, make sure to follow these additional guidelines: - -1. Ensure that the code passes the necessary tests. Run the appropriate testing - commands specific to this repository. - -2. Format the code to adhere to the consistent style used in the repository. Use - the provided formatting tools or scripts. - -3. Check the code for common mistakes and errors using linting tools specific to - this repository. - -## Documentation - -Proper documentation is crucial for maintaining the project and helping other -developers understand the codebase. Follow these guidelines for documenting -APIs: - -### JavaScript and TypeScript - -Use JSDoc comments to document publicly exposed APIs and types. Place the JSDoc -comments immediately before the statement they apply to. Refer to the -[JSDoc documentation](https://jsdoc.app/) for more information on writing -effective JSDoc comments. - -Thank you for your interest in contributing to `deno_generate`! We appreciate -your contributions and look forward to reviewing your pull requests. diff --git a/README.md b/README.md index 7ce4a81..b7cda49 100644 --- a/README.md +++ b/README.md @@ -1,358 +1,188 @@ -# `deno generate` proof-of-concept ![thunder_deno](https://cdn.discordapp.com/emojis/811013541846319105.gif?size=24&quality=lossless) +# `deno generate` proof-of-concept -[![deno doc](https://doc.deno.land/badge.svg)](https://deno.land/x/generate) +🦕 Userland implementation of [`go generate`] for Deno -Automate code generation by running procedures defined in comment annotations. - -This repository is a proof-of-concept for the `deno generate` subcommand as -proposed in [Deno issue #19176](https://github.com/denoland/deno/issues/19176). - -## Usage - -To use this tool, add a `//deno:generate` comment in your program with the -command you want to run. For example: +
```ts -//deno:generate deno run https://deno.land/std/examples/cat.ts README.md +// main.ts +//deno:generate deno run -A npm:peggy@3 css.pegjs +import { parse as parseCSS } from "./css.js"; +const ast = parseCSS(`a:hover { background: red; }`) +console.log(ast); ``` -### Running the CLI tool +
-To generate code using the CLI tool, run the tool from `deno.land/x` with the -command: - -```sh -deno run -Ar https://deno.land/x/generate/cli/main.ts +```pegjs +// css.pegjs +start + = stylesheet:stylesheet comment* { return stylesheet; } +stylesheet + = charset:(CHARSET_SYM STRING ";")? (S / CDO / CDC)* + imports:(import (CDO S* / CDC S*)*)* + rules:((ruleset / media / page) (CDO S* / CDC S*)*)* +// ... ``` -If you are interested in installing the script, refer to the -[Installation](#installation) section. +
```sh -deno-generate --help -deno-generate +deno_generate +ls +#=> main.ts css.pegjs css.js +deno run -A main.ts +#=> [Large AST] ``` -You can also define a task in your `deno.jsonc` file to run the CLI tool in your -Deno project: +
-```jsonc -{ - "tasks": { - "generate": "deno run -Ar https://deno.land/x/generate/cli/main.ts " - } -} -``` +🦕 Designed for Deno-based projects \ +🏭 Works great for code generation \ +🔒 Use `--allow-run=onlyme` to limit permissions \ +⚠️ Unofficial `deno` subcommand -### Installation +👀 Check out the [Feature request: Add `deno generate` subcommand · Issue #19176 +· denoland/deno] discussion if you're interested in seeing a command like +`deno generate` included in the Deno CLI. -Alternatively, you can install the script as a command and run it locally: +This is a _proof-of-concept_. Use `deno task` in any serious projects. -```sh -deno install -rf -A https://deno.land/x/generate/cli/main.ts --name=deno-generate -deno-generate -``` +## Install -
- -Install from script source (Expand for more information) - +![Deno](https://img.shields.io/static/v1?style=for-the-badge&message=Deno&color=000000&logo=Deno&logoColor=FFFFFF&label=) ```sh -git clone https://github.com/ethanthatonekid/deno_generate.git -cd deno_generate -deno install -rf -A cli/main.ts --name=deno-generate +deno install -A https://deno.land/x/deno_generate/main.ts +deno_generate ``` -
- -### Security - -The CLI tool only executes `//deno:generate` comments that run commands allowed -by the `--allow-run` flag. This security measure is in place to prevent the -execution of malicious code. You can set this flag during installation or each -time you run the script. - -You can find more information about the `--allow-run` flag in the -[Deno permissions documentation](https://deno.land/manual/basics/permissions#permissions-list). - -### Use cases - -Code generation is an important programming technique because generated files -can automate repetitive or complex tasks, improve code consistency and -maintainability, and save developers time and effort. - -As for use cases, your imagination is the limit. Here are a few: - -1. Generating code from templates: Developers can define templates for commonly - used code patterns and use the CLI tool to automatically generate code that - follows those patterns. -2. Generating code from schemas: If a project uses a schema to define data - models or API specifications, developers can create generators that generate - code based on that schema. -3. Generating tests: Developers can define test templates that cover common - testing scenarios and use the CLI tool to automatically generate tests for - their code. -4. Generating code from annotations: Developers can add annotations to their - code that define which generators to run and how to run them. - -## Examples - -The `deno generate` subcommand is capable of facilitating the generation of code -in the Deno ecosystem. Developers use code generation to generate code for all -kinds of use cases. - -You can find more examples in the [`examples` directory](examples). - -### Run a script +You can also just run it directly when needed: -Deno scripts should be able to invoke another Deno in its `//deno:generate` -statement: - -#### `generator.ts` +```sh +deno run -A https://deno.land/x/deno_generate@1/main.ts +``` -The provided code generates basic TypeScript code using a for loop to export -constants. +Or add a task to your `deno.json`: -```ts -//deno:generate deno run -A generate.ts -for (let i = 0; i < 10; i++) { - console.log(`export const example${i} = ${i};`); +```jsonc +// deno.json +{ + "tasks": { + "generate": "deno run -A https://deno.land/x/deno_generate@1/main.ts" + } } ``` -> **Note** While this example works for simple cases, it is advisable to utilize -> a widely-used library such as [ts-morph](https://github.com/dsherret/ts-morph) -> for more comprehensive and complete examples. `ts-morph` is a TypeScript -> Compiler API wrapper for static analysis and programmatic code changes. This -> module provides an extensive set of features and utilities, simplifying the -> handling of complex code generation scenarios. By leveraging ts-morph, -> developers can ensure a more robust, maintainable code generation process. - -##### `generate.ts` +## Usage -```ts -// Create a child process using Deno.Command, running the "generate.ts" script. -const generatorChild = new Deno.Command(Deno.execPath(), { - args: ["run", "generator.ts"], - stdin: "piped", - stdout: "piped", -}).spawn(); - -// Create another child process, running deno fmt. -const fmtChild = new Deno.Command(Deno.execPath(), { - args: ["fmt", "-"], - stdin: "piped", - stdout: "piped", -}).spawn(); - -// Pipe the current process stdin to the child process stdin. -generatorChild.stdout.pipeTo(fmtChild.stdin); - -// Close the child process stdin. -generatorChild.stdin.close(); - -// Pipe the child process stdout to a writable file named "generated.ts". -fmtChild.stdout.pipeTo( - Deno.openSync("generated.ts", { write: true, create: true }).writable, -); -``` +![Deno](https://img.shields.io/static/v1?style=for-the-badge&message=Deno&color=000000&logo=Deno&logoColor=FFFFFF&label=) -### Generate OpenAPI types +You can use `deno:generate` to run Deno scripts that generate data for your app +to consume. Here's an example that fetches data at generation time: -OpenAPI is a JSON-based specification that represents comprehensive API details, -providing a formal and professional representation of the API specifications. -One of the most common use cases of OpenAPI is to generate API clients, -simplifying the development process by automatically generating code based on -the defined API specifications. OpenAPI schemas offer versatile applications and -integrations, enabling a wide range of possibilities for API design and -development. +
```ts -//deno:generate deno run -A npm:openapi-typescript@6.2.4 ./examples/github_api.json -o ./examples/github_api.ts +// app.ts +//deno:generate deno run -A ./generate_data.ts +import data from "./data.js"; +console.log(data); ``` -### Generate static website with Lume + -Lume is a website framework for the Deno ecosystem. Entire static websites are -generated by Lume with a single command. -[See more](https://github.com/lumeland/lume). - -```ts -//deno:generate deno run -A https://deno.land/x/lume@v1.17.3/cli.ts --src ./examples/lume --dest ./examples/lume/_site +```sh +deno_generate +ls +#=> app.ts generate_data.ts data.js +deno run -A app.ts +#=> { message: "Hello world!" } ``` -### Generate `deno_bindgen` bindings - -This tool aims to simplify glue code generation for Deno FFI libraries written -in Rust. [See more](https://github.com/denoland/deno_bindgen). +
```ts -//deno:generate deno run -A https://deno.land/x/deno_bindgen@0.8.0/cli.ts +// generate_data.ts +const response = await fetch("https://example.org/data.json"); +const json = response.json(); +const js = `export default ${JSON.stringify(json)}`; +await Deno.writeTextFile("data.js", js); ``` -### Generate deno-embedder file - -deno-embedder is a tool that simplifies the development and distribution of Deno -applications, particularly when access to static files (.txt, .png, etc.) is -required at runtime. It allows you to create an embedder.ts file that -encompasses both configuration and the main function call, providing benefits -such as IDE-based type-checking. -[See more](https://github.com/NfNitLoop/deno-embedder). +
-#### `with_embedder.ts` +💡 Pro tip: Use the `--allow-run=mycommand` flag with `deno run` to limit which +commands `deno_generate` can spawn. -```ts -//deno:generate deno run -A embedder.ts -import examplesDir from "../embedder_static/dir.ts"; +⚠️ It's recommended to commit any generated files to source control so that any +user of your package can import it directly from GitHub without needing to run +`deno_generate` themselves with a build step on their own machine. -const exampleFile = await examplesDir.load("with_embedder.ts"); -console.log("You are currently reading:", await exampleFile.text()); -``` +Here's another example of a `//deno:generate` command to generate TypeScript types from a JSON schema: -Bundlee is a deno-embedder alternative. +
```ts -import { Bundlee } from "https://deno.land/x/bundlee/mod.ts"; - -//deno:generate deno run -A https://deno.land/x/bundlee@0.9.4/bundlee.ts --bundle static/ bundle.json -const staticFiles = await Bundlee.load("bundle.json"); -``` +// api.ts +//deno:generate deno run -A npm:json-schema-to-typescript@13 req.schema.json req.d.ts +import type RequestType from "./req.d.ts" +//deno:generate deno run -A npm:json-schema-to-typescript@13 res.schema.json res.d.ts +import type ResponseType from "./res.d.ts" +Deno.serve((request) => { + const req = await request.json() as RequestType + const res: ResponseType = { + from: "server@example.com", + to: "user@example.org", + messageHTML: marked(req.messageMD), + }; + return Response.json(res); +}); +``` + +
-### Generate `deno doc` JSON - -#### `with_generate_docs.ts` - -```ts -//deno:generate deno run -A generate_docs.ts -import doc from "./doc.json" assert { type: "json" }; -``` - -#### `generate_docs.ts` - -```ts -// Create a child process running `deno doc --json`. -const child = new Deno.Command(Deno.execPath(), { - args: ["doc", "--json"], - stdin: "piped", - stdout: "piped", -}).spawn(); - -// Pipe the child process stdout to a writable file named "doc.json". -child.stdout.pipeTo( - Deno.openSync("doc.json", { write: true, create: true }).writable, -); -``` - -### Conventions - -To ensure a consistent developer experience, we recommend following these -conventions when using the CLI tool: - -#### Pre-commit - -To enhance your development workflow, we recommend implementing a pre-commit -hook in your project's Git repository. Follow these steps to set it up: - -1. Create a file named "pre-commit" (without any file extension) within your - project's ".git/hooks" directory. -2. Ensure that the file is executable by running the following command in your - terminal: - -```bash -chmod +x .git/hooks/pre-commit -``` - -3. Open the "pre-commit" file in a text editor and add the following code: - -```bash -#!/bin/bash - -# Run generators before committing. -deno task generate - -# Check if any files have changed. -git diff --exit-code +```jsonc +// req.schema.json +{ + "type": "object", + "properties": { + "messageMD": { "type": "string" } + }, + "required": ["messageMD"] +} ``` -#### Linguist generated - -When dealing with code generation, there are situations where generated files -should not be visible to developers during a pull request. To address this, a -setting can be used to differentiate their changes, ensuring a cleaner and more -focused code review. On GitHub, you can achieve this by marking specific files -with the "linguist-generated" attribute in a ".gitattributes" file[^1]. This -attribute allows you to hide these files by default in diffs and exclude them -from contributing to the repository language statistics. - -To implement this, follow these steps: + -1. Create a ".gitattributes" file in your project's root directory if it doesn't - already exist. -2. Open the ".gitattributes" file in a text editor and include the relevant file - patterns along with the "linguist-generated" attribute. For example: +```jsonc +// res.schema.json +{ + "type": "object", + "properties": { + "from": { "type": "string" }, + "to": { "type": "string" }, + "messageHTML": { "type": "string" } + }, + "required": ["from", "to", "messageHTML"] +} -```bash -# Marking generated files -*.generated.extension linguist-generated ``` -3. Save the file and commit it to your repository. - -Now, when viewing pull requests or generating diffs on GitHub, the marked files -will be hidden by default, providing a more streamlined code review process and -excluding them from language statistics calculations. - -## Development - -To run the tool from source, use the following command: +
```sh -deno run -A cli/main.ts --verbose ./examples/embedder/with_embedder.ts -``` - -### Testing - -To run the existing unit tests, use the following command: - -```bash -deno test -``` - -### Formatting and linting - -To format your code and check for lint errors, use the following command: - -This process cleans your code and identifies common errors. - -```bash -deno task all +deno_generate +ls +#=> api.ts req.schema.json res.schema.json req.d.ts res.d.ts +deno run -A api.ts ``` -The `all` task is defined in [`deno.jsonc`](deno.jsonc) and executes the -following tasks: +
-- `fmt`: Formats the code using - [Deno fmt](https://deno.land/manual/tools/formatter) -- `lint`: Runs [Deno lint](https://deno.land/manual/tools/linter) to identify - linting errors - -You can run each task individually using the following commands: - -```bash -deno task fmt -``` - -```bash -deno task lint -``` - -### Contributing - -Contributions are welcome! Read the [contributing guide](CONTRIBUTING.md) for -more information. - -### FAQ +ℹ `deno_generate` only scans one level deep for `deno:generate` comments. If +you want to recursively scan for `deno:generate` comments, specify a glob +pattern like `deno_generate "./**"` #### Why do I want to put `//deno:generate ` in source code instead of just in `deno task`? @@ -383,12 +213,7 @@ a single place—the shared module—and have the updates reflect in both files depend on it. This not only reduces code duplication but also improves maintainability by ensuring consistency throughout the project. -### License - -[MIT](LICENSE) - ---- - -Programmed with 🦕 by [**@EthanThatOneKid**](https://etok.codes/) - -[^1]: + +[Feature request: Add `deno generate` subcommand · Issue #19176 · denoland/deno]: https://github.com/denoland/deno/issues/19176 +[`go generate`]: https://go.googlesource.com/proposal/+/refs/heads/master/design/go-generate.md + diff --git a/cli/flags.ts b/cli/flags.ts deleted file mode 100644 index 07b5749..0000000 --- a/cli/flags.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { - globToRegExp, - isAbsolute, - isGlob, - join, - parse, - toFileUrl, -} from "../deps.ts"; -import type { GenerateOptions } from "../mod.ts"; - -/** - * toGenerateOptions converts CLI flags to GenerateOptions. - */ -export function toGenerateOptions(flags: GenerateFlags): GenerateOptions { - return { - rootSpecifiers: flags["_"] - .map(String) - .map((specifier) => - isAbsolute(specifier) - ? specifier - : toFileUrl(join(Deno.cwd(), specifier)).href - ), - dryRun: flags["dry-run"], - trace: flags["trace"], - verbose: flags["verbose"], - run: flags["run"].map((pattern) => new RegExp(pattern)), - skip: flags["skip"].map((pattern) => new RegExp(pattern)), - include: flags["include"] - .map((specifierOrGlob) => - isGlob(specifierOrGlob) - ? globToRegExp(specifierOrGlob) - : new RegExp(specifierOrGlob) - ), - exclude: flags["exclude"] - .map((specifierOrGlob) => - isGlob(specifierOrGlob) - ? globToRegExp(specifierOrGlob) - : new RegExp(specifierOrGlob) - ), - }; -} - -/** - * GenerateFlags is the CLI flags. - */ -export type GenerateFlags = ReturnType; - -/** - * parseGenerateFlags parses the program's CLI flags. - */ -export function parseGenerateFlags(args: string[]) { - return parse(args, { - "--": false, - stopEarly: true, - string: ["run", "skip", "include", "exclude"], - collect: ["run", "skip", "include", "exclude"], - boolean: ["help", "dry-run", "verbose", "trace"], - alias: { - "dry-run": ["n"], - "verbose": ["v"], - "trace": ["x"], - "run": ["r"], - "skip": ["s"], - "help": ["h"], - }, - default: { - "dry-run": false, - "verbose": false, - "trace": false, - }, - }); -} diff --git a/cli/help.ts b/cli/help.ts deleted file mode 100644 index 96693aa..0000000 --- a/cli/help.ts +++ /dev/null @@ -1,100 +0,0 @@ -/** - * HELP is the help text for the generate command. - */ -export const HELP = - `Automate code generation by running procedures defined in comment annotations. - -Usage: - deno https://deno.land/x/generate/main.ts [...] [options] - -Options: - -n, --dry-run Print the commands that would be run without - actually running them. - -r, --run Select directives to run by matching against the - directive text as-is. - -s, --skip Select directives to skip by matching against the - directive text as-is. - -v, --verbose Print the module specifier and directive text of - each directive when running the corresponding - generator. - -x, --trace Print the commands as they are run. - -Examples: - deno-generate - deno-generate myfile1.ts - deno-generate myfile1.ts myfile2.ts - deno-generate myfile1.ts --dry-run - -Deno generate scans a module graph for directives, which are lines starting -with the comment: - - //deno:generate [arguments...] - -where command is the generator corresponding to an executable file that can be -run locally. To run, arguments are passed to the generator. The generator is run -from the directory containing the directive. - -Note: No space in between "//" and "deno:generate". - -The deno generate command does not parse the file, so lines that look like -directives in comments or strings will be treated as directives. - -The arguments to the directive are space-separated tokens or double-quoted -strings passed to the generator as arguments. Quoted strings are evaluated -before execution. - -To convey to humans and tools that code is generated, generated source files -should have a comment of the form: - - ^// Code generated .* DO NOT EDIT\.$ - -The line must appear before the first non-comment, non-blank line of the file. - -Deno generate sets several variables when running generators: - - $DENO_OS The operating system of the host running deno generate. - $DENO_MODULE The module specifier of the module containing the directive. - $DENO_LINE The line number of the directive within the file. - $DENO_CHARACTER The character number of the directive within the file. - $DENO_DIR The directory containing the file containing the directive. - $DOLLAR A dollar sign ($). This is useful for escaping the $ in shell commands. - Literature: https://go-review.googlesource.com/c/go/+/8091 - -A directive may define a command alias for the file: - - //deno:generate -command [arguments...] - -where, for the remainder of this source file, the command is replaced -by the arguments. This can be used to create aliases for long commands or to -define arguments that are common to multiple directives. For example: - - //deno:generate -command cat deno run --allow-read https://deno.land/std/examples/cat.ts - (...) - //deno:generate deno run ./generate_code.ts - -The -command directive may appear anywhere in the file, but it is usually placed -at the top of the file, before any directives that use it. - -The --run flag specifies a regular expression to select directives to run by -matching against the directive text as-is. The regular expression does not need -to match the entire text of the directive, but it must match at least one -character. The default is to run all directives. - -The --skip flag specifies a regular expression to select directives to skip by -matching against the directive text as-is. The regular expression does not need -to match the entire text of the directive, but it must match at least one -character. The default is to not skip any directives. - -The --dry-run flag (-n) prints the commands that would be run without actually -running them. - -The --verbose flag (-v) prints the module specifier and directive -text of each directive when running the corresponding generator. - -The --trace flag (-x) prints the commands as they are run. - -You can also combine these flags to modify deno generate's behavior in different -ways. For example, deno generate -n -v mod.ts will run generate in dry run mode -and print more detailed information about the commands that it would run, while -deno generate -v -x will run generate in verbose mode and print the commands -that it is running as it runs them.`; diff --git a/cli/main.ts b/cli/main.ts deleted file mode 100644 index 37c4643..0000000 --- a/cli/main.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { handlers, setup } from "../deps.ts"; -import { GENERATE, generate } from "../mod.ts"; -import { parseGenerateFlags, toGenerateOptions } from "./flags.ts"; -import { HELP } from "./help.ts"; - -if (import.meta.main) { - await main(); -} - -/** - * main is the entrypoint of the program. - */ -async function main() { - // Parse flags. - const flags = parseGenerateFlags(Deno.args); - if (flags.help || flags._.length === 0) { - console.log(HELP); - Deno.exit(0); - } - - // Convert flags to options. - const options = toGenerateOptions(flags); - - // Setup logging. - await setup({ - loggers: { - [GENERATE]: { - // Suppress log messages if not verbose. - level: options.verbose ? "DEBUG" : "WARNING", - handlers: ["console"], - }, - }, - handlers: { - console: new handlers.ConsoleHandler("DEBUG"), - }, - }); - - // Run the generators. - await generate(options); -} diff --git a/deno.jsonc b/deno.jsonc deleted file mode 100644 index c99a125..0000000 --- a/deno.jsonc +++ /dev/null @@ -1,13 +0,0 @@ -{ - "lock": "./deno.lock", - "tasks": { - "lint": "deno lint", - "fmt": "deno fmt", - "generate": "deno task generate:example-01 && deno task generate:example-02", - "generate:example-01": "deno run -A cli/main.ts --verbose ./examples/typescript/generator.ts", - "generate:example-02": "deno run -A cli/main.ts --verbose --exclude ^https:// ./examples/embedder/with_embedder.ts", - "udd": "deno run -r -A https://deno.land/x/udd/main.ts dev_deps.ts deps.ts && deno task lock", - "lock": "deno cache --lock=deno.lock --lock-write dev_deps.ts deps.ts", - "all": "deno task udd && deno task lint && deno task fmt" - } -} diff --git a/deno.lock b/deno.lock deleted file mode 100644 index 957beb4..0000000 --- a/deno.lock +++ /dev/null @@ -1,184 +0,0 @@ -{ - "version": "2", - "remote": { - "https://deno.land/std@0.170.0/fmt/colors.ts": "03ad95e543d2808bc43c17a3dd29d25b43d0f16287fe562a0be89bf632454a12", - "https://deno.land/std@0.175.0/_util/asserts.ts": "178dfc49a464aee693a7e285567b3d0b555dc805ff490505a8aae34f9cfb1462", - "https://deno.land/std@0.175.0/_util/os.ts": "d932f56d41e4f6a6093d56044e29ce637f8dcc43c5a90af43504a889cf1775e3", - "https://deno.land/std@0.175.0/async/abortable.ts": "73acfb3ed7261ce0d930dbe89e43db8d34e017b063cf0eaa7d215477bf53442e", - "https://deno.land/std@0.175.0/async/deadline.ts": "b98e50d2c42399af03ad13bbb8cf59dadb9f0cd5d70648cc0c3b9202d75ab565", - "https://deno.land/std@0.175.0/async/debounce.ts": "adab11d04ca38d699444ac8a9d9856b4155e8dda2afd07ce78276c01ea5a4332", - "https://deno.land/std@0.175.0/async/deferred.ts": "42790112f36a75a57db4a96d33974a936deb7b04d25c6084a9fa8a49f135def8", - "https://deno.land/std@0.175.0/async/delay.ts": "73aa04cec034c84fc748c7be49bb15cac3dd43a57174bfdb7a4aec22c248f0dd", - "https://deno.land/std@0.175.0/async/mod.ts": "f04344fa21738e5ad6bea37a6bfffd57c617c2d372bb9f9dcfd118a1b622e576", - "https://deno.land/std@0.175.0/async/mux_async_iterator.ts": "70c7f2ee4e9466161350473ad61cac0b9f115cff4c552eaa7ef9d50c4cbb4cc9", - "https://deno.land/std@0.175.0/async/pool.ts": "fd082bd4aaf26445909889435a5c74334c017847842ec035739b4ae637ae8260", - "https://deno.land/std@0.175.0/async/retry.ts": "5efa3ba450ac0c07a40a82e2df296287b5013755d232049efd7ea2244f15b20f", - "https://deno.land/std@0.175.0/async/tee.ts": "47e42d35f622650b02234d43803d0383a89eb4387e1b83b5a40106d18ae36757", - "https://deno.land/std@0.175.0/encoding/base64.ts": "7de04c2f8aeeb41453b09b186480be90f2ff357613b988e99fabb91d2eeceba1", - "https://deno.land/std@0.175.0/fs/_util.ts": "65381f341af1ff7f40198cee15c20f59951ac26e51ddc651c5293e24f9ce6f32", - "https://deno.land/std@0.175.0/fs/copy.ts": "14214efd94fc3aa6db1e4af2b4b9578e50f7362b7f3725d5a14ad259a5df26c8", - "https://deno.land/std@0.175.0/fs/empty_dir.ts": "c3d2da4c7352fab1cf144a1ecfef58090769e8af633678e0f3fabaef98594688", - "https://deno.land/std@0.175.0/fs/ensure_dir.ts": "724209875497a6b4628dfb256116e5651c4f7816741368d6c44aab2531a1e603", - "https://deno.land/std@0.175.0/fs/ensure_file.ts": "c38602670bfaf259d86ca824a94e6cb9e5eb73757fefa4ebf43a90dd017d53d9", - "https://deno.land/std@0.175.0/fs/ensure_link.ts": "c0f5b2f0ec094ed52b9128eccb1ee23362a617457aa0f699b145d4883f5b2fb4", - "https://deno.land/std@0.175.0/fs/ensure_symlink.ts": "2955cc8332aeca9bdfefd05d8d3976b94e282b0f353392a71684808ed2ffdd41", - "https://deno.land/std@0.175.0/fs/eol.ts": "f1f2eb348a750c34500741987b21d65607f352cf7205f48f4319d417fff42842", - "https://deno.land/std@0.175.0/fs/exists.ts": "b8c8a457b71e9d7f29b9d2f87aad8dba2739cbe637e8926d6ba6e92567875f8e", - "https://deno.land/std@0.175.0/fs/expand_glob.ts": "45d17e89796a24bd6002e4354eda67b4301bb8ba67d2cac8453cdabccf1d9ab0", - "https://deno.land/std@0.175.0/fs/mod.ts": "bc3d0acd488cc7b42627044caf47d72019846d459279544e1934418955ba4898", - "https://deno.land/std@0.175.0/fs/move.ts": "4cb47f880e3f0582c55e71c9f8b1e5e8cfaacb5e84f7390781dd563b7298ec19", - "https://deno.land/std@0.175.0/fs/walk.ts": "ea95ffa6500c1eda6b365be488c056edc7c883a1db41ef46ec3bf057b1c0fe32", - "https://deno.land/std@0.175.0/path/_constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0", - "https://deno.land/std@0.175.0/path/_interface.ts": "6471159dfbbc357e03882c2266d21ef9afdb1e4aa771b0545e90db58a0ba314b", - "https://deno.land/std@0.175.0/path/_util.ts": "d7abb1e0dea065f427b89156e28cdeb32b045870acdf865833ba808a73b576d0", - "https://deno.land/std@0.175.0/path/common.ts": "ee7505ab01fd22de3963b64e46cff31f40de34f9f8de1fff6a1bd2fe79380000", - "https://deno.land/std@0.175.0/path/glob.ts": "d479e0a695621c94d3fd7fe7abd4f9499caf32a8de13f25073451c6ef420a4e1", - "https://deno.land/std@0.175.0/path/mod.ts": "4b83694ac500d7d31b0cdafc927080a53dc0c3027eb2895790fb155082b0d232", - "https://deno.land/std@0.175.0/path/posix.ts": "8b7c67ac338714b30c816079303d0285dd24af6b284f7ad63da5b27372a2c94d", - "https://deno.land/std@0.175.0/path/separator.ts": "0fb679739d0d1d7bf45b68dacfb4ec7563597a902edbaf3c59b50d5bcadd93b1", - "https://deno.land/std@0.175.0/path/win32.ts": "d186344e5583bcbf8b18af416d13d82b35a317116e6460a5a3953508c3de5bba", - "https://deno.land/std@0.201.0/assert/_constants.ts": "8a9da298c26750b28b326b297316cdde860bc237533b07e1337c021379e6b2a9", - "https://deno.land/std@0.201.0/assert/_diff.ts": "1a3c044aedf77647d6cac86b798c6417603361b66b54c53331b312caeb447aea", - "https://deno.land/std@0.201.0/assert/_format.ts": "a69126e8a469009adf4cf2a50af889aca364c349797e63174884a52ff75cf4c7", - "https://deno.land/std@0.201.0/assert/assert.ts": "9a97dad6d98c238938e7540736b826440ad8c1c1e54430ca4c4e623e585607ee", - "https://deno.land/std@0.201.0/assert/assert_almost_equals.ts": "e15ca1f34d0d5e0afae63b3f5d975cbd18335a132e42b0c747d282f62ad2cd6c", - "https://deno.land/std@0.201.0/assert/assert_array_includes.ts": "6856d7f2c3544bc6e62fb4646dfefa3d1df5ff14744d1bca19f0cbaf3b0d66c9", - "https://deno.land/std@0.201.0/assert/assert_equals.ts": "d8ec8a22447fbaf2fc9d7c3ed2e66790fdb74beae3e482855d75782218d68227", - "https://deno.land/std@0.201.0/assert/assert_exists.ts": "407cb6b9fb23a835cd8d5ad804e2e2edbbbf3870e322d53f79e1c7a512e2efd7", - "https://deno.land/std@0.201.0/assert/assert_false.ts": "a9962749f4bf5844e3fa494257f1de73d69e4fe0e82c34d0099287552163a2dc", - "https://deno.land/std@0.201.0/assert/assert_greater.ts": "ae2158a2d19313bf675bf7251d31c6dc52973edb12ac64ac8fc7064152af3e63", - "https://deno.land/std@0.201.0/assert/assert_greater_or_equal.ts": "1439da5ebbe20855446cac50097ac78b9742abe8e9a43e7de1ce1426d556e89c", - "https://deno.land/std@0.201.0/assert/assert_instance_of.ts": "3aedb3d8186e120812d2b3a5dea66a6e42bf8c57a8bd927645770bd21eea554c", - "https://deno.land/std@0.201.0/assert/assert_is_error.ts": "c21113094a51a296ffaf036767d616a78a2ae5f9f7bbd464cd0197476498b94b", - "https://deno.land/std@0.201.0/assert/assert_less.ts": "aec695db57db42ec3e2b62e97e1e93db0063f5a6ec133326cc290ff4b71b47e4", - "https://deno.land/std@0.201.0/assert/assert_less_or_equal.ts": "5fa8b6a3ffa20fd0a05032fe7257bf985d207b85685fdbcd23651b70f928c848", - "https://deno.land/std@0.201.0/assert/assert_match.ts": "c4083f80600bc190309903c95e397a7c9257ff8b5ae5c7ef91e834704e672e9b", - "https://deno.land/std@0.201.0/assert/assert_not_equals.ts": "9f1acab95bd1f5fc9a1b17b8027d894509a745d91bac1718fdab51dc76831754", - "https://deno.land/std@0.201.0/assert/assert_not_instance_of.ts": "0c14d3dfd9ab7a5276ed8ed0b18c703d79a3d106102077ec437bfe7ed912bd22", - "https://deno.land/std@0.201.0/assert/assert_not_match.ts": "3796a5b0c57a1ce6c1c57883dd4286be13a26f715ea662318ab43a8491a13ab0", - "https://deno.land/std@0.201.0/assert/assert_not_strict_equals.ts": "ca6c6d645e95fbc873d25320efeb8c4c6089a9a5e09f92d7c1c4b6e935c2a6ad", - "https://deno.land/std@0.201.0/assert/assert_object_match.ts": "d8fc2867cfd92eeacf9cea621e10336b666de1874a6767b5ec48988838370b54", - "https://deno.land/std@0.201.0/assert/assert_rejects.ts": "45c59724de2701e3b1f67c391d6c71c392363635aad3f68a1b3408f9efca0057", - "https://deno.land/std@0.201.0/assert/assert_strict_equals.ts": "b1f538a7ea5f8348aeca261d4f9ca603127c665e0f2bbfeb91fa272787c87265", - "https://deno.land/std@0.201.0/assert/assert_string_includes.ts": "b821d39ebf5cb0200a348863c86d8c4c4b398e02012ce74ad15666fc4b631b0c", - "https://deno.land/std@0.201.0/assert/assert_throws.ts": "63784e951475cb7bdfd59878cd25a0931e18f6dc32a6077c454b2cd94f4f4bcd", - "https://deno.land/std@0.201.0/assert/assertion_error.ts": "4d0bde9b374dfbcbe8ac23f54f567b77024fb67dbb1906a852d67fe050d42f56", - "https://deno.land/std@0.201.0/assert/equal.ts": "9f1a46d5993966d2596c44e5858eec821859b45f783a5ee2f7a695dfc12d8ece", - "https://deno.land/std@0.201.0/assert/fail.ts": "c36353d7ae6e1f7933d45f8ea51e358c8c4b67d7e7502028598fe1fea062e278", - "https://deno.land/std@0.201.0/assert/mod.ts": "37c49a26aae2b254bbe25723434dc28cd7532e444cf0b481a97c045d110ec085", - "https://deno.land/std@0.201.0/assert/unimplemented.ts": "d56fbeecb1f108331a380f72e3e010a1f161baa6956fd0f7cf3e095ae1a4c75a", - "https://deno.land/std@0.201.0/assert/unreachable.ts": "4600dc0baf7d9c15a7f7d234f00c23bca8f3eba8b140286aaca7aa998cf9a536", - "https://deno.land/std@0.201.0/bytes/concat.ts": "d26d6f3d7922e6d663dacfcd357563b7bf4a380ce5b9c2bbe0c8586662f25ce2", - "https://deno.land/std@0.201.0/bytes/copy.ts": "939d89e302a9761dcf1d9c937c7711174ed74c59eef40a1e4569a05c9de88219", - "https://deno.land/std@0.201.0/flags/mod.ts": "0948466fc437f017f00c0b972a422b3dc3317a790bcf326429d23182977eaf9f", - "https://deno.land/std@0.201.0/fmt/colors.ts": "87544aa2bc91087bb37f9c077970c85bfb041b48e4c37356129d7b450a415b6f", - "https://deno.land/std@0.201.0/fs/exists.ts": "cb59a853d84871d87acab0e7936a4dac11282957f8e195102c5a7acb42546bb8", - "https://deno.land/std@0.201.0/io/buf_reader.ts": "0bd8ad26255945b5f418940db23db03bee0c160dbb5ae4627e2c0be3b361df6a", - "https://deno.land/std@0.201.0/io/buf_writer.ts": "48c33c8f00b61dcbc7958706741cec8e59810bd307bc6a326cbd474fe8346dfd", - "https://deno.land/std@0.201.0/io/read_lines.ts": "c526c12a20a9386dc910d500f9cdea43cba974e853397790bd146817a7eef8cc", - "https://deno.land/std@0.201.0/log/handlers.ts": "3a0883f65567f59a9a88e44c972b24b924621bc28ead91af11d7a6da93c4a64c", - "https://deno.land/std@0.201.0/log/levels.ts": "6309147664e9e008cd6671610f2505c4c95f181f6bae4816a84b33e0aec66859", - "https://deno.land/std@0.201.0/log/logger.ts": "180c50a07c43a556dc5794e913c82946399e89d683201d01c8f0091e1e4ae3fc", - "https://deno.land/std@0.201.0/log/mod.ts": "a274d2129c8d08d4c96e0fb165a595e6c730b5130b437a9ce04364156bfe955a", - "https://deno.land/std@0.201.0/path/_basename.ts": "057d420c9049821f983f784fd87fa73ac471901fb628920b67972b0f44319343", - "https://deno.land/std@0.201.0/path/_constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0", - "https://deno.land/std@0.201.0/path/_dirname.ts": "355e297236b2218600aee7a5301b937204c62e12da9db4b0b044993d9e658395", - "https://deno.land/std@0.201.0/path/_extname.ts": "eaaa5aae1acf1f03254d681bd6a8ce42a9cb5b7ff2213a9d4740e8ab31283664", - "https://deno.land/std@0.201.0/path/_format.ts": "4a99270d6810f082e614309164fad75d6f1a483b68eed97c830a506cc589f8b4", - "https://deno.land/std@0.201.0/path/_from_file_url.ts": "6eadfae2e6f63ad9ee46b26db4a1b16583055c0392acedfb50ed2fc694b6f581", - "https://deno.land/std@0.201.0/path/_interface.ts": "6471159dfbbc357e03882c2266d21ef9afdb1e4aa771b0545e90db58a0ba314b", - "https://deno.land/std@0.201.0/path/_is_absolute.ts": "05dac10b5e93c63198b92e3687baa2be178df5321c527dc555266c0f4f51558c", - "https://deno.land/std@0.201.0/path/_join.ts": "815f5e85b042285175b1492dd5781240ce126c23bd97bad6b8211fe7129c538e", - "https://deno.land/std@0.201.0/path/_normalize.ts": "a19ec8706b2707f9dd974662a5cd89fad438e62ab1857e08b314a8eb49a34d81", - "https://deno.land/std@0.201.0/path/_os.ts": "d932f56d41e4f6a6093d56044e29ce637f8dcc43c5a90af43504a889cf1775e3", - "https://deno.land/std@0.201.0/path/_parse.ts": "0f9b0ff43682dd9964eb1c4398610c4e165d8db9d3ac9d594220217adf480cfa", - "https://deno.land/std@0.201.0/path/_relative.ts": "27bdeffb5311a47d85be26d37ad1969979359f7636c5cd9fcf05dcd0d5099dc5", - "https://deno.land/std@0.201.0/path/_resolve.ts": "7a3616f1093735ed327e758313b79c3c04ea921808ca5f19ddf240cb68d0adf6", - "https://deno.land/std@0.201.0/path/_to_file_url.ts": "a141e4a525303e1a3a0c0571fd024552b5f3553a2af7d75d1ff3a503dcbb66d8", - "https://deno.land/std@0.201.0/path/_to_namespaced_path.ts": "0d5f4caa2ed98ef7a8786286df6af804b50e38859ae897b5b5b4c8c5930a75c8", - "https://deno.land/std@0.201.0/path/_util.ts": "4e191b1bac6b3bf0c31aab42e5ca2e01a86ab5a0d2e08b75acf8585047a86221", - "https://deno.land/std@0.201.0/path/basename.ts": "bdfa5a624c6a45564dc6758ef2077f2822978a6dbe77b0a3514f7d1f81362930", - "https://deno.land/std@0.201.0/path/common.ts": "ee7505ab01fd22de3963b64e46cff31f40de34f9f8de1fff6a1bd2fe79380000", - "https://deno.land/std@0.201.0/path/dirname.ts": "b6533f4ee4174a526dec50c279534df5345836dfdc15318400b08c62a62a39dd", - "https://deno.land/std@0.201.0/path/extname.ts": "62c4b376300795342fe1e4746c0de518b4dc9c4b0b4617bfee62a2973a9555cf", - "https://deno.land/std@0.201.0/path/format.ts": "110270b238514dd68455a4c54956215a1aff7e37e22e4427b7771cefe1920aa5", - "https://deno.land/std@0.201.0/path/from_file_url.ts": "9f5cb58d58be14c775ec2e57fc70029ac8b17ed3bd7fe93e475b07280adde0ac", - "https://deno.land/std@0.201.0/path/glob.ts": "593e2c3573883225c25c5a21aaa8e9382a696b8e175ea20a3b6a1471ad17aaed", - "https://deno.land/std@0.201.0/path/is_absolute.ts": "0b92eb35a0a8780e9f16f16bb23655b67dace6a8e0d92d42039e518ee38103c1", - "https://deno.land/std@0.201.0/path/join.ts": "31c5419f23d91655b08ec7aec403f4e4cd1a63d39e28f6e42642ea207c2734f8", - "https://deno.land/std@0.201.0/path/mod.ts": "6e1efb0b13121463aedb53ea51dabf5639a3172ab58c89900bbb72b486872532", - "https://deno.land/std@0.201.0/path/normalize.ts": "6ea523e0040979dd7ae2f1be5bf2083941881a252554c0f32566a18b03021955", - "https://deno.land/std@0.201.0/path/parse.ts": "be8de342bb9e1924d78dc4d93c45215c152db7bf738ec32475560424b119b394", - "https://deno.land/std@0.201.0/path/posix.ts": "0a1c1952d132323a88736d03e92bd236f3ed5f9f079e5823fae07c8d978ee61b", - "https://deno.land/std@0.201.0/path/relative.ts": "8bedac226afd360afc45d451a6c29fabceaf32978526bcb38e0c852661f66c61", - "https://deno.land/std@0.201.0/path/resolve.ts": "133161e4949fc97f9ca67988d51376b0f5eef8968a6372325ab84d39d30b80dc", - "https://deno.land/std@0.201.0/path/separator.ts": "40a3e9a4ad10bef23bc2cd6c610291b6c502a06237c2c4cd034a15ca78dedc1f", - "https://deno.land/std@0.201.0/path/to_file_url.ts": "00e6322373dd51ad109956b775e4e72e5f9fa68ce2c6b04e4af2a6eed3825d31", - "https://deno.land/std@0.201.0/path/to_namespaced_path.ts": "1b1db3055c343ab389901adfbda34e82b7386bcd1c744d54f9c1496ee0fd0c3d", - "https://deno.land/std@0.201.0/path/win32.ts": "8b3f80ef7a462511d5e8020ff490edcaa0a0d118f1b1e9da50e2916bdd73f9dd", - "https://deno.land/std@0.201.0/testing/asserts.ts": "b4e4b1359393aeff09e853e27901a982c685cb630df30426ed75496961931946", - "https://deno.land/std@0.91.0/encoding/base64.ts": "eecae390f1f1d1cae6f6c6d732ede5276bf4b9cd29b1d281678c054dc5cc009e", - "https://deno.land/x/cliffy@v0.25.7/_utils/distance.ts": "02af166952c7c358ac83beae397aa2fbca4ad630aecfcd38d92edb1ea429f004", - "https://deno.land/x/cliffy@v0.25.7/command/_errors.ts": "a9bd23dc816b32ec96c9b8f3057218241778d8c40333b43341138191450965e5", - "https://deno.land/x/cliffy@v0.25.7/command/_utils.ts": "9ab3d69fabab6c335b881b8a5229cbd5db0c68f630a1c307aff988b6396d9baf", - "https://deno.land/x/cliffy@v0.25.7/command/command.ts": "a2b83c612acd65c69116f70dec872f6da383699b83874b70fcf38cddf790443f", - "https://deno.land/x/cliffy@v0.25.7/command/completions/_bash_completions_generator.ts": "43b4abb543d4dc60233620d51e69d82d3b7c44e274e723681e0dce2a124f69f9", - "https://deno.land/x/cliffy@v0.25.7/command/completions/_fish_completions_generator.ts": "d0289985f5cf0bd288c05273bfa286b24c27feb40822eb7fd9d7fee64e6580e8", - "https://deno.land/x/cliffy@v0.25.7/command/completions/_zsh_completions_generator.ts": "14461eb274954fea4953ee75938821f721da7da607dc49bcc7db1e3f33a207bd", - "https://deno.land/x/cliffy@v0.25.7/command/completions/bash.ts": "053aa2006ec327ccecacb00ba28e5eb836300e5c1bec1b3cfaee9ddcf8189756", - "https://deno.land/x/cliffy@v0.25.7/command/completions/complete.ts": "58df61caa5e6220ff2768636a69337923ad9d4b8c1932aeb27165081c4d07d8b", - "https://deno.land/x/cliffy@v0.25.7/command/completions/fish.ts": "9938beaa6458c6cf9e2eeda46a09e8cd362d4f8c6c9efe87d3cd8ca7477402a5", - "https://deno.land/x/cliffy@v0.25.7/command/completions/mod.ts": "aeef7ec8e319bb157c39a4bab8030c9fe8fa327b4c1e94c9c1025077b45b40c0", - "https://deno.land/x/cliffy@v0.25.7/command/completions/zsh.ts": "8b04ab244a0b582f7927d405e17b38602428eeb347a9968a657e7ea9f40e721a", - "https://deno.land/x/cliffy@v0.25.7/command/deprecated.ts": "bbe6670f1d645b773d04b725b8b8e7814c862c9f1afba460c4d599ffe9d4983c", - "https://deno.land/x/cliffy@v0.25.7/command/deps.ts": "275b964ce173770bae65f6b8ebe9d2fd557dc10292cdd1ed3db1735f0d77fa1d", - "https://deno.land/x/cliffy@v0.25.7/command/help/_help_generator.ts": "f7c349cb2ddb737e70dc1f89bcb1943ca9017a53506be0d4138e0aadb9970a49", - "https://deno.land/x/cliffy@v0.25.7/command/help/mod.ts": "09d74d3eb42d21285407cda688074c29595d9c927b69aedf9d05ff3f215820d3", - "https://deno.land/x/cliffy@v0.25.7/command/mod.ts": "d0a32df6b14028e43bb2d41fa87d24bc00f9662a44e5a177b3db02f93e473209", - "https://deno.land/x/cliffy@v0.25.7/command/type.ts": "24e88e3085e1574662b856ccce70d589959648817135d4469fab67b9cce1b364", - "https://deno.land/x/cliffy@v0.25.7/command/types.ts": "ae02eec0ed7a769f7dba2dd5d3a931a61724b3021271b1b565cf189d9adfd4a0", - "https://deno.land/x/cliffy@v0.25.7/command/types/action_list.ts": "33c98d449617c7a563a535c9ceb3741bde9f6363353fd492f90a74570c611c27", - "https://deno.land/x/cliffy@v0.25.7/command/types/boolean.ts": "3879ec16092b4b5b1a0acb8675f8c9250c0b8a972e1e4c7adfba8335bd2263ed", - "https://deno.land/x/cliffy@v0.25.7/command/types/child_command.ts": "f1fca390c7fbfa7a713ca15ef55c2c7656bcbb394d50e8ef54085bdf6dc22559", - "https://deno.land/x/cliffy@v0.25.7/command/types/command.ts": "325d0382e383b725fd8d0ef34ebaeae082c5b76a1f6f2e843fee5dbb1a4fe3ac", - "https://deno.land/x/cliffy@v0.25.7/command/types/enum.ts": "2178345972adf7129a47e5f02856ca3e6852a91442a1c78307dffb8a6a3c6c9f", - "https://deno.land/x/cliffy@v0.25.7/command/types/file.ts": "8618f16ac9015c8589cbd946b3de1988cc4899b90ea251f3325c93c46745140e", - "https://deno.land/x/cliffy@v0.25.7/command/types/integer.ts": "29864725fd48738579d18123d7ee78fed37515e6dc62146c7544c98a82f1778d", - "https://deno.land/x/cliffy@v0.25.7/command/types/number.ts": "aeba96e6f470309317a16b308c82e0e4138a830ec79c9877e4622c682012bc1f", - "https://deno.land/x/cliffy@v0.25.7/command/types/string.ts": "e4dadb08a11795474871c7967beab954593813bb53d9f69ea5f9b734e43dc0e0", - "https://deno.land/x/cliffy@v0.25.7/command/upgrade/mod.ts": "17e2df3b620905583256684415e6c4a31e8de5c59066eb6d6c9c133919292dc4", - "https://deno.land/x/cliffy@v0.25.7/command/upgrade/provider.ts": "d6fb846043232cbd23c57d257100c7fc92274984d75a5fead0f3e4266dc76ab8", - "https://deno.land/x/cliffy@v0.25.7/command/upgrade/provider/deno_land.ts": "24f8d82e38c51e09be989f30f8ad21f9dd41ac1bb1973b443a13883e8ba06d6d", - "https://deno.land/x/cliffy@v0.25.7/command/upgrade/provider/github.ts": "99e1b133dd446c6aa79f69e69c46eb8bc1c968dd331c2a7d4064514a317c7b59", - "https://deno.land/x/cliffy@v0.25.7/command/upgrade/provider/nest_land.ts": "0e07936cea04fa41ac9297f32d87f39152ea873970c54cb5b4934b12fee1885e", - "https://deno.land/x/cliffy@v0.25.7/command/upgrade/upgrade_command.ts": "3640a287d914190241ea1e636774b1b4b0e1828fa75119971dd5304784061e05", - "https://deno.land/x/cliffy@v0.25.7/flags/_errors.ts": "f1fbb6bfa009e7950508c9d491cfb4a5551027d9f453389606adb3f2327d048f", - "https://deno.land/x/cliffy@v0.25.7/flags/_utils.ts": "340d3ecab43cde9489187e1f176504d2c58485df6652d1cdd907c0e9c3ce4cc2", - "https://deno.land/x/cliffy@v0.25.7/flags/_validate_flags.ts": "16eb5837986c6f6f7620817820161a78d66ce92d690e3697068726bbef067452", - "https://deno.land/x/cliffy@v0.25.7/flags/deprecated.ts": "a72a35de3cc7314e5ebea605ca23d08385b218ef171c32a3f135fb4318b08126", - "https://deno.land/x/cliffy@v0.25.7/flags/flags.ts": "68a9dfcacc4983a84c07ba19b66e5e9fccd04389fad215210c60fb414cc62576", - "https://deno.land/x/cliffy@v0.25.7/flags/types.ts": "7452ea5296758fb7af89930349ce40d8eb9a43b24b3f5759283e1cb5113075fd", - "https://deno.land/x/cliffy@v0.25.7/flags/types/boolean.ts": "4c026dd66ec9c5436860dc6d0241427bdb8d8e07337ad71b33c08193428a2236", - "https://deno.land/x/cliffy@v0.25.7/flags/types/integer.ts": "b60d4d590f309ddddf066782d43e4dc3799f0e7d08e5ede7dc62a5ee94b9a6d9", - "https://deno.land/x/cliffy@v0.25.7/flags/types/number.ts": "610936e2d29de7c8c304b65489a75ebae17b005c6122c24e791fbed12444d51e", - "https://deno.land/x/cliffy@v0.25.7/flags/types/string.ts": "e89b6a5ce322f65a894edecdc48b44956ec246a1d881f03e97bbda90dd8638c5", - "https://deno.land/x/cliffy@v0.25.7/table/border.ts": "2514abae4e4f51eda60a5f8c927ba24efd464a590027e900926b38f68e01253c", - "https://deno.land/x/cliffy@v0.25.7/table/cell.ts": "1d787d8006ac8302020d18ec39f8d7f1113612c20801b973e3839de9c3f8b7b3", - "https://deno.land/x/cliffy@v0.25.7/table/deps.ts": "5b05fa56c1a5e2af34f2103fd199e5f87f0507549963019563eae519271819d2", - "https://deno.land/x/cliffy@v0.25.7/table/layout.ts": "46bf10ae5430cf4fbb92f23d588230e9c6336edbdb154e5c9581290562b169f4", - "https://deno.land/x/cliffy@v0.25.7/table/row.ts": "5f519ba7488d2ef76cbbf50527f10f7957bfd668ce5b9169abbc44ec88302645", - "https://deno.land/x/cliffy@v0.25.7/table/table.ts": "ec204c9d08bb3ff1939c5ac7412a4c9ed7d00925d4fc92aff9bfe07bd269258d", - "https://deno.land/x/cliffy@v0.25.7/table/utils.ts": "187bb7dcbcfb16199a5d906113f584740901dfca1007400cba0df7dcd341bc29", - "https://deno.land/x/deno_graph@0.54.0/deno_graph_wasm.generated.js": "c401baf605e5537ebe4b25c98fa0b539f1b1ecbb075c2643b30882c5a0e1a3c4", - "https://deno.land/x/deno_graph@0.54.0/loader.ts": "a2e757383908f4a51659fe1b1203386887ebb17756bac930a64856d613d8d57d", - "https://deno.land/x/deno_graph@0.54.0/media_type.ts": "a89a1b38d07c160e896de9ceb99285ba8391940140558304171066b5c3ef7609", - "https://deno.land/x/deno_graph@0.54.0/mod.ts": "e4bdddf09d8332394ac4b2e7084f7f4fbbbf09dff344cac9bd60f5e20b4f12e0", - "https://deno.land/x/dir@1.5.1/data_local_dir/mod.ts": "91eb1c4bfadfbeda30171007bac6d85aadacd43224a5ed721bbe56bc64e9eb66", - "https://deno.land/x/embedder@v1.1.1/_src/util.ts": "ad5e7d892ac708f6d7d42b4bfcf2a8f11aa7e65ebd6a733728a5d6192e2409b0", - "https://deno.land/x/embedder@v1.1.1/embed.ts": "262813eb86d21b062928aaca3dea8d6a3f90ca6831458e77a8e0977c25e188ee", - "https://deno.land/x/embedder@v1.1.1/mod.ts": "b1a1b3c0bac5c3db40ef60d1f3e5a4fb9fcdd9314078014adb3f4e9da162f2dc", - "https://deno.land/x/embedder@v1.1.1/plugins/plugins.ts": "71f5f3350019755f9f96927f5229273f49ee87ae263d54c901c2173c69fd52f2", - "https://deno.land/x/wasmbuild@0.14.1/cache.ts": "89eea5f3ce6035a1164b3e655c95f21300498920575ade23161421f5b01967f4", - "https://deno.land/x/wasmbuild@0.14.1/loader.ts": "d98d195a715f823151cbc8baa3f32127337628379a02d9eb2a3c5902dbccfc02" - } -} diff --git a/deps.ts b/deps.ts deleted file mode 100644 index 5dc8313..0000000 --- a/deps.ts +++ /dev/null @@ -1,17 +0,0 @@ -export { parse } from "https://deno.land/std@0.201.0/flags/mod.ts"; -export { - dirname, - globToRegExp, - isAbsolute, - isGlob, - join, - toFileUrl, -} from "https://deno.land/std@0.201.0/path/mod.ts"; -export { - getLogger, - handlers, - setup, -} from "https://deno.land/std@0.201.0/log/mod.ts"; -export { readLines } from "https://deno.land/std@0.201.0/io/read_lines.ts"; - -export { createGraph } from "https://deno.land/x/deno_graph@0.54.0/mod.ts"; diff --git a/dev_deps.ts b/dev_deps.ts deleted file mode 100644 index 2a5fb97..0000000 --- a/dev_deps.ts +++ /dev/null @@ -1,6 +0,0 @@ -export { - assertEquals, - assertThrows, -} from "https://deno.land/std@0.201.0/testing/asserts.ts"; - -export * as embedder from "https://deno.land/x/embedder@v1.1.1/mod.ts"; diff --git a/examples/embedder/embedder.ts b/examples/embedder/embedder.ts deleted file mode 100644 index 9242327..0000000 --- a/examples/embedder/embedder.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { embedder } from "../../dev_deps.ts"; - -const embedderOptions: embedder.DevOptions = { - importMeta: import.meta, - mappings: [ - { sourceDir: "./", destDir: "../embedder_static" }, - ], -}; - -if (import.meta.main) { - await embedder.main({ - options: embedderOptions, - args: ["build"], - }); -} diff --git a/examples/embedder/with_embedder.ts b/examples/embedder/with_embedder.ts deleted file mode 100644 index c0175d3..0000000 --- a/examples/embedder/with_embedder.ts +++ /dev/null @@ -1,5 +0,0 @@ -//deno:generate deno run -A embedder.ts -import examplesDir from "../embedder_static/dir.ts"; - -const exampleFile = await examplesDir.load("with_embedder.ts"); -console.log("You are currently reading:", await exampleFile.text()); diff --git a/examples/embedder_static/dir.ts b/examples/embedder_static/dir.ts deleted file mode 100644 index 9aed2f3..0000000 --- a/examples/embedder_static/dir.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { E } from "https://deno.land/x/embedder@v1.1.1/embed.ts"; -import f0 from "./embedder.ts_.ts"; -import f1 from "./with_embedder.ts_.ts"; - -export default E({ - "embedder.ts": f0, - "with_embedder.ts": f1, -}); diff --git a/examples/embedder_static/embedder.ts_.ts b/examples/embedder_static/embedder.ts_.ts deleted file mode 100644 index c72763d..0000000 --- a/examples/embedder_static/embedder.ts_.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { F } from "https://deno.land/x/embedder@v1.1.1/embed.ts"; -export default F({ - size: 307, - encoded: ` -aW1wb3J0IHsgZW1iZWRkZXIgfSBmcm9tICIuLi8uLi9kZXZfZGVwcy50cyI7Cgpjb25zdCBlbWJlZGRlck9wdGlvbnM6IGVtYmVkZGVyLkRldk9wdGlvbnMg -PSB7CiAgaW1wb3J0TWV0YTogaW1wb3J0Lm1ldGEsCiAgbWFwcGluZ3M6IFsKICAgIHsgc291cmNlRGlyOiAiLi8iLCBkZXN0RGlyOiAiLi4vZW1iZWRkZXJf -c3RhdGljIiB9LAogIF0sCn07CgppZiAoaW1wb3J0Lm1ldGEubWFpbikgewogIGF3YWl0IGVtYmVkZGVyLm1haW4oewogICAgb3B0aW9uczogZW1iZWRkZXJP -cHRpb25zLAogICAgYXJnczogWyJidWlsZCJdLAogIH0pOwp9Cg==`, -}); diff --git a/examples/embedder_static/with_embedder.ts_.ts b/examples/embedder_static/with_embedder.ts_.ts deleted file mode 100644 index 1049e79..0000000 --- a/examples/embedder_static/with_embedder.ts_.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { F } from "https://deno.land/x/embedder@v1.1.1/embed.ts"; -export default F({ - size: 227, - encoded: ` -Ly9kZW5vOmdlbmVyYXRlIGRlbm8gcnVuIC1BIGVtYmVkZGVyLnRzCmltcG9ydCBleGFtcGxlc0RpciBmcm9tICIuLi9lbWJlZGRlcl9zdGF0aWMvZGlyLnRz -IjsKCmNvbnN0IGV4YW1wbGVGaWxlID0gYXdhaXQgZXhhbXBsZXNEaXIubG9hZCgid2l0aF9lbWJlZGRlci50cyIpOwpjb25zb2xlLmxvZygiWW91IGFyZSBj -dXJyZW50bHkgcmVhZGluZzoiLCBhd2FpdCBleGFtcGxlRmlsZS50ZXh0KCkpOwo=`, -}); diff --git a/examples/typescript/generate.ts b/examples/typescript/generate.ts deleted file mode 100644 index b70b596..0000000 --- a/examples/typescript/generate.ts +++ /dev/null @@ -1,24 +0,0 @@ -// Create a child process using Deno.Command, running the "generate.ts" script. -const generatorChild = new Deno.Command(Deno.execPath(), { - args: ["run", "generator.ts"], - stdin: "piped", - stdout: "piped", -}).spawn(); - -// Create another child process, running deno fmt. -const fmtChild = new Deno.Command(Deno.execPath(), { - args: ["fmt", "-"], - stdin: "piped", - stdout: "piped", -}).spawn(); - -// Pipe the current process stdin to the child process stdin. -generatorChild.stdout.pipeTo(fmtChild.stdin); - -// Close the child process stdin. -generatorChild.stdin.close(); - -// Pipe the child process stdout to a writable file named "generated.ts". -fmtChild.stdout.pipeTo( - Deno.openSync("generated.ts", { write: true, create: true }).writable, -); diff --git a/examples/typescript/generated.ts b/examples/typescript/generated.ts deleted file mode 100644 index a4d1289..0000000 --- a/examples/typescript/generated.ts +++ /dev/null @@ -1,10 +0,0 @@ -export const example0 = 0; -export const example1 = 1; -export const example2 = 2; -export const example3 = 3; -export const example4 = 4; -export const example5 = 5; -export const example6 = 6; -export const example7 = 7; -export const example8 = 8; -export const example9 = 9; diff --git a/examples/typescript/generator.ts b/examples/typescript/generator.ts deleted file mode 100644 index 472544a..0000000 --- a/examples/typescript/generator.ts +++ /dev/null @@ -1,4 +0,0 @@ -//deno:generate deno run -A generate.ts -for (let i = 0; i < 10; i++) { - console.log(`export const example${i} = ${i};`); -} diff --git a/generate.ts b/generate.ts deleted file mode 100644 index 0e457d7..0000000 --- a/generate.ts +++ /dev/null @@ -1,171 +0,0 @@ -import { createGraph, dirname, getLogger } from "./deps.ts"; -import type { ParsedComment } from "./parse/mod.ts"; -import { parseComments } from "./parse/mod.ts"; - -/** - * generate runs procedures defined in comment annotations. - */ -export async function generate(options: GenerateOptions): Promise { - logger().info("Generating..."); - const graph = await createGraph(options.rootSpecifiers); - for (const module of graph.modules) { - // Exclude the module if it matches any of the exclude patterns. - const exclude = options.exclude.some((re) => re.test(module.specifier)); - if (exclude) { - continue; - } - - // Include the module if it matches any of the include patterns or if - // there are no include patterns. - const include = options.include.length === 0 || - options.include.some((re) => re.test(module.specifier)); - if (!include) { - continue; - } - - // Read the module's directives. - const specifier = new URL(module.specifier); - logger().info(`Generating ${specifier}`); - let comments: ParsedComment[] = []; - try { - comments = await parseComments( - Deno.openSync(specifier, { "read": true }), - ); - } catch (error) { - logger().error(`Error parsing ${specifier}: ${error}`); - continue; - } - const aliases = new Map(); - for (const comment of comments) { - // Skip the comment if it matches any of the skip patterns. - const skip = options.skip.some((re) => re.test(comment.original)); - if (skip) { - continue; - } - - // Run the comment if it matches any of the run patterns or if there - // are no run patterns. - const run = options.run.length === 0 || - options.run.some((re) => re.test(comment.original)); - if (!run) { - continue; - } - - // Add the comment to the aliases map if it is an alias. - if (comment.alias) { - aliases.set(comment.alias, comment.args); - continue; - } - - // Construct the command details. - const args = aliases.has(comment.args[0]) - ? aliases.get(comment.args[0])!.concat(comment.args.slice(1)) - : comment.args; - const details = args.join(" "); - if (options.trace) { - console.log(details); - } - - // Skip the command if this is a dry run. - if (options.dryRun) { - continue; - } - - // Run the generator. - const cwd = new URL(dirname(module.specifier)); - const command = new Deno.Command(args[0], { - args: args.slice(1), - cwd, - stdout: "piped", - stderr: "piped", - }); - const output = command.outputSync(); - if (options.verbose) { - Deno.stdout.writable.getWriter().write(output.stdout); - Deno.stderr.writable.getWriter().write(output.stderr); - } - - // Stop running generators in this module if the process failed. - if (!output.success) { - logger().error(`Failed to execute "${details}"`); - break; - } - - // Log the success. - logger().info(`Successfully executed "${details}"`); - } - } -} - -/** - * GenerateOptions is the options for generate function. - */ -export interface GenerateOptions { - /** - * rootSpecifiers is a URL string of the root module specifier to build - * the graph from or array of URL strings. - */ - rootSpecifiers: string[]; - - /** - * dryRun is whether to run the directives without making any changes. - */ - dryRun: boolean; - - /** - * trace is whether to trace the execution of the directives. This prints - * the commands as they are executed. - */ - trace: boolean; - - /** - * verbose is whether to print verbose output. - */ - verbose: boolean; - - /** - * run is a list of procedure patterns to run. It specifies a regular - * expression to select directives to run by matching against the directive - * text as-is. The regular expression does not need to match the entire - * text of the directive, but it must match at least one character. The - * default is to run all directives. - */ - run: RegExp[]; - - /** - * skip is a list of procedure patterns to skip. It specifies a regular - * expression to select directives to skip by matching against the directive - * text as-is. The regular expression does not need to match the entire text - * of the directive, but it must match at least one character. The default is - * to not skip any directives. - * - * In the event that a command matches both a run and skip regular expressions, - * the command is skipped. - */ - skip: RegExp[]; - - /** - * include is a list of files to include. It specifies a glob pattern to - * select files to include. The default is to include all files. - */ - include: RegExp[]; - - /** - * exclude is a list of files to exclude. It specifies which files to exclude - * from the include list. The default is to exclude no files. If a file is - * matched by both the include and exclude lists, it is excluded. - */ - exclude: RegExp[]; -} - -/** - * logger is the logger for generate function. - */ -export function logger() { - return getLogger(GENERATE); -} - -/** - * GENERATE is the directive name for generate function. - */ -export const GENERATE = "generate"; diff --git a/main.ts b/main.ts new file mode 100644 index 0000000..cadaf2c --- /dev/null +++ b/main.ts @@ -0,0 +1,170 @@ +import process from "node:process"; +import { parseArgs } from "node:util"; +import { basename, delimiter, dirname, join, resolve } from "node:path"; +import { readFile } from "node:fs/promises"; +import { $ } from "npm:execa@^8.0.1"; +import { glob } from "npm:glob@^10.3.10"; +import * as ShellQuote from "npm:shell-quote@^1.8.1"; + +const version = import.meta.url.match(/\/deno_generate@(\d+\.\d+\.\d+)\//)?.[1]; + +const help = `\ +deno_generate ${version ? `v${version}` : ""} + +USAGE + deno install -A https://deno.land/x/deno_generate@1/main.ts + deno_generate + # OR + deno run -A https://deno.land/x/deno_generate@1/main.ts + # OR + echo '{"tasks":{"generate":"deno run -A https://deno.land/x/deno_generate@1/main.ts"}}' > deno.json + deno task generate + +OPTIONS + --help: print this help message + --version: print the version + --run : only run generators whose command contains this substring + --skip : skip generators whose command contains this substring + --verbose, -v: print the path of each file being processed + --dry-run, -n: print the command without running it + --xtrace, -x: print the command before running it + --show-output, -O: show the output of the commands +`; + +const options = { + help: { type: "boolean" }, + version: { type: "boolean" }, + run: { type: "string" }, + skip: { type: "string" }, + verbose: { type: "boolean", short: "v" }, + "dry-run": { type: "boolean", short: "n" }, + xtrace: { type: "boolean", short: "x" }, + "show-output": { type: "boolean", short: "O" }, +}; // satisfies ParseArgsConfig['options'] +// https://github.com/denoland/deno/issues/22363 +const { values, positionals } = parseArgs({ options, allowPositionals: true, args: process.argv.slice(2) }); + +if (values.help) { + console.log(help); + process.exit(0); +} +if (values.version) { + console.log(version); + process.exit(0); +} + +const globPatterns = positionals.length + ? positionals + : ["./*.{js,mjs,cjs,jsx,ts,mts,cts,tsx}"]; +let sourceFilePaths = await glob(globPatterns, { + ignore: ["**/node_modules/**"], + absolute: true, +}); +sourceFilePaths = sourceFilePaths.filter((x) => + /\.[cm]?[jt]sx?$/.test(x) && !/\.d\.[cm]?[jt]sx?$/.test(x) && + !/\.d\.[^\.]+\.[cm]?[jt]sx?$/.test(x) +); + +if (values.run && values.skip) { + throw new DOMException( + "cannot specify both --run and --skip", + "SyntaxError", + ); +} + +const DENOROOT = process.env.DENO_DIR || resolve(process.execPath, "../.."); +const PATH = join(DENOROOT, "bin") + delimiter + process.env.PATH; +const DOLLAR = "$"; + +for (const path of sourceFilePaths) { + if (values.verbose) { + console.log(path); + } + + const code = await readFile(path, "utf8"); + + if ( + /^(#!.*\r?\n)?((\/\/.*)?\r?\n)*\/\/ Code generated .* DO NOT EDIT\.\r?\n/ + .test(code) + ) { + continue; + } + + // const generators = new Map(); + + for ( + const match of code.matchAll(/^\/\/deno:generate\s+(\S+)(?:\s+(.*))?/gm) + ) { + if (values.skip && match[0].includes(values.skip)) { + continue; + } else if (values.run && !match[0].includes(values.run)) { + continue; + } + + const DENOFILE = basename(path); + const DENOLINE = code.slice(0, match.index!).match(/^/gm)!.length; + const PWD = dirname(path); + const env = { + ...process.env, + DENOFILE, + DENOLINE, + DENOROOT, + DOLLAR, + PWD, + PATH, + }; + + // if (match[1] === "-command") { + // if (!match[2]) { + // throw new DOMException("missing command alias value", "SyntaxError"); + // } + // const aliasMatch = match[2].match(/^(\S+)\s+(\S+)(?:\s+(.*))?$/); + // if (!aliasMatch) { + // throw new DOMException( + // "invalid command alias value", + // "SyntaxError", + // ); + // } + // const key = aliasMatch[1]; + // const cmd = aliasMatch[2]; + // const args = aliasMatch[3] ?? null; + // generators.set(key, { cmd, args }); + // continue; + // } + + let cmd: string; + let args: string; + // const alias = generators.get(match[1]); + // if (alias) { + // cmd = alias.cmd; + // args = [alias.args, match[2]].filter(x => x).join(" "); + // } else { + cmd = match[1]; + args = match[2] ?? ""; + // } + const argv = ShellQuote.parse(args, env); + argv.unshift(cmd); + + if (values["dry-run"]) { + console.log(`${path}:${DENOLINE} ${ShellQuote.quote(argv)}`); + } else { + if (values.xtrace) { + console.log(`${path}:${DENOLINE} ${ShellQuote.quote(argv)}`); + } + const { exitCode, signal, all } = await $({ + cwd: PWD, + all: true, + reject: false, + })`${argv}`; + if (signal) { + console.error(`${path}:${DENOLINE} raised ${signal}`); + all && console.error(all); + } else if (exitCode) { + console.error(`${path}:${DENOLINE} exited with code ${exitCode}`); + console.error(all); + } else if (values["show-output"]) { + all && console.log(all); + } + } + } +} diff --git a/main_test.ts b/main_test.ts new file mode 100644 index 0000000..79f3b06 --- /dev/null +++ b/main_test.ts @@ -0,0 +1,64 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import process from "node:process"; +import { rmSync } from "node:fs"; +import { basename, dirname, join } from "node:path"; +import { mkdir, readFile, writeFile } from "node:fs/promises"; +import { fileURLToPath } from "node:url"; +import { $ } from "npm:execa@^8.0.1"; +import { temporaryDirectory } from "npm:tempy@^3.1.0"; + +type Tree = { [path: string]: string | Tree }; +async function temporaryTree(tree: Tree): Promise { + async function f(tree: Tree, root: string) { + for (const [path, content] of Object.entries(tree)) { + if (typeof content === "string") { + await writeFile(join(root, path), content); + } else { + await mkdir(join(root, path)); + await f(content, join(root, path)); + } + } + } + const root = temporaryDirectory(); + await f(tree, root); + process.on("exit", () => { + rmSync(root, { recursive: true, force: true }); + }); + return root; +} + +const deno_generate = [ + "deno", + "run", + "-A", + fileURLToPath(import.meta.resolve("./main.ts")), +]; + +test("echo info dry-run", async () => { + const cwd = await temporaryTree({ + "main.ts": `//deno:generate echo $DENOFILE $DENOLINE $PWD`, + }); + const $t = $({ cwd, all: true }); + const { all } = await $t`${deno_generate} -n`; + assert.match(all!, /.echo main\.ts 1/); +}); + +test("echo info real", async () => { + const cwd = await temporaryTree({ + "main.ts": `//deno:generate echo $DENOFILE $DENOLINE $PWD`, + }); + const $t = $({ cwd, all: true }); + const { all } = await $t`${deno_generate} -O`; + assert.match(all!, /^main\.ts 1/m); +}); + +// test("uses alias", async () => { +// const cwd = await temporaryTree({ +// "main.ts": `\ +// //deno:generate -command doit echo $DENOFILE $DENOLINE $PWD +// //deno:generate doit`, +// }); +// const $t = $({ cwd, stdio: "inherit" }); +// await $t`${deno_generate} -vxnO`; +// }); diff --git a/mod.ts b/mod.ts deleted file mode 100644 index 4304b27..0000000 --- a/mod.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./generate.ts"; diff --git a/parse/mod.ts b/parse/mod.ts deleted file mode 100644 index 2bb163f..0000000 --- a/parse/mod.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./parse.ts"; diff --git a/parse/parse.ts b/parse/parse.ts deleted file mode 100644 index a6a8128..0000000 --- a/parse/parse.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { readLines } from "../deps.ts"; -import { quotedSplit } from "./quoted_split.ts"; - -/** - * ParsedComment is a command that is generated by a //deno:generate - * comment. - */ -export interface ParsedComment { - args: string[]; - original: string; - line: number; - character: number; - alias?: string; -} - -/** - * DIRECTIVE_PATTERN is the pattern that matches a //deno:generate comment. - */ -export const DIRECTIVE_PATTERN = /^\/\/deno:generate\s+/; - -/** - * This is a very simple parser that only looks for comments - * because to run arbitrary code generation commands, we only - * need to parse the file to determine the comments. With each - * comment, we return the line and character of the comment so that - * we can tell the user where errors are. - * - * Implements dynamic programming to get the line and character of the comment. - */ -export async function parseComments( - reader: Deno.Reader, -): Promise { - const comments: ParsedComment[] = []; - let currentLine = 0; - for await (const line of readLines(reader)) { - currentLine++; - if (!DIRECTIVE_PATTERN.test(line)) { - continue; - } - - comments.push( - fromComment(line, currentLine, 0), - ); - } - - return comments; -} - -/** - * Example commands all parse to the same thing: - * //deno:generate echo "Hello World!" - */ -function fromComment( - comment: string, - line: number, - character: number, -): ParsedComment { - // Remove the leading // and trailing whitespace - const original = comment - .replace(DIRECTIVE_PATTERN, "") - .trim(); - - // Split on spaces, but not spaces inside quotes. - const args = quotedSplit(original); - - // If the first arg is an alias, then we need to remove it from the - // command and return it separately. - if (args[0] === "-command") { - return { args: args.slice(2), alias: args[1], line, character, original }; - } - - return { args, line, character, original }; -} diff --git a/parse/quoted_split.ts b/parse/quoted_split.ts deleted file mode 100644 index 7a3397f..0000000 --- a/parse/quoted_split.ts +++ /dev/null @@ -1,46 +0,0 @@ -/** - * quotedSplit is a simple shell-like string splitter that splits on spaces - * unless the space is quoted. - * - * @see https://tip.golang.org/src/cmd/internal/quoted/quoted.go - */ -export function quotedSplit(s: string): string[] { - // Split fields allowing '' or "" around elements. - // Quotes further inside the string do not count. - const f: string[] = []; - while (s.length > 0) { - while (s.length > 0 && isSpaceByte(s[0])) { - s = s.slice(1); - } - if (s.length === 0) { - break; - } - // Accepted quoted string. No unescaping inside. - if (s[0] === '"' || s[0] === "'") { - const quote = s[0]; - s = s.slice(1); - let i = 0; - while (i < s.length && s[i] !== quote) { - i++; - } - if (i >= s.length) { - throw new Error(`Unterminated ${quote} string.`); - } - f.push(s.slice(0, i)); - s = s.slice(i + 1); - continue; - } - let i = 0; - while (i < s.length && !isSpaceByte(s[i])) { - i++; - } - f.push(s.slice(0, i)); - s = s.slice(i); - } - return f; -} - -// isSpaceByte returns true if the given character is a space character. -function isSpaceByte(c: string): boolean { - return c === " " || c === "\t" || c === "\n" || c === "\r"; -} diff --git a/parse/quoted_split_bench.ts b/parse/quoted_split_bench.ts deleted file mode 100644 index 77882a4..0000000 --- a/parse/quoted_split_bench.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { quotedSplit } from "./quoted_split.ts"; - -Deno.bench("quotedSplit small", () => { - quotedSplit("a b"); -}); - -Deno.bench("quotedSplit big", () => { - quotedSplit( - "a b c d e f g h i j k l m n o p q r s t u v w x y z", - ); -}); diff --git a/parse/quoted_split_test.ts b/parse/quoted_split_test.ts deleted file mode 100644 index 614f30f..0000000 --- a/parse/quoted_split_test.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { assertEquals, assertThrows } from "../dev_deps.ts"; - -import { quotedSplit } from "./quoted_split.ts"; - -Deno.test("split splits an empty string", () => { - const got = quotedSplit(""); - assertEquals(got, []); -}); - -Deno.test("split splits a string with a space", () => { - const got = quotedSplit(" "); - assertEquals(got, []); -}); - -Deno.test("split splits a string with one word", () => { - const got = quotedSplit("a"); - assertEquals(got, ["a"]); -}); - -Deno.test("split splits a string with a leading space", () => { - const got = quotedSplit(" a"); - assertEquals(got, ["a"]); -}); - -Deno.test("split splits a string with a trailing space", () => { - const got = quotedSplit("a "); - assertEquals(got, ["a"]); -}); - -Deno.test("split splits a string with two words", () => { - const got = quotedSplit("a b"); - assertEquals(got, ["a", "b"]); -}); - -Deno.test("split splits a string with two words and a multi-space", () => { - const got = quotedSplit("a b"); - assertEquals(got, ["a", "b"]); -}); - -Deno.test("split splits a string with two words and a tab", () => { - const got = quotedSplit("a\tb"); - assertEquals(got, ["a", "b"]); -}); - -Deno.test("split splits a string with two words and a newline", () => { - const got = quotedSplit("a\nb"); - assertEquals(got, ["a", "b"]); -}); - -Deno.test("split splits a string with a single-quoted word", () => { - const got = quotedSplit("'a b'"); - assertEquals(got, ["a b"]); -}); - -Deno.test("split splits a string with a double-quoted word", () => { - const got = quotedSplit('"a b"'); - assertEquals(got, ["a b"]); -}); - -Deno.test("split splits a string with a single-quoted and double-quoted word", () => { - const got = quotedSplit(`'a '"b "`); - assertEquals(got, ["a ", "b "]); -}); - -Deno.test("split splits a string with a both quotes contained within each other", () => { - const got = quotedSplit(`'a "'"'b"`); - assertEquals(got, [`a "`, `'b`]); -}); - -Deno.test("split escapes single quote", () => { - const got = quotedSplit(`\\'`); - assertEquals(got, [`\\'`]); -}); - -Deno.test("Split throws on unterminated single quote", () => { - assertThrows(() => quotedSplit(`'a`), Error, "Unterminated ' string"); -});