This article will dive into Deno and create a command line tool for searching for text in files and folders. We will use various API methods provided by Deno to read and write to the file system.
In the previous article, we built a command line tool using Deno to make requests to third-party APIs. In this article, we will temporarily ignore network operations and build a tool that allows you to search for text in files and folders within the current directory - tools like grep.
Note: The tools we build are not as optimized and efficient as grep, and we are not aiming to replace it! The purpose of building such a tool is to be familiar with Deno's file system API.
Key Points
- Deno's file system API helps create command-line tools for searching for text in files and directories, similar to grep tools, but not as optimized.
- Using Yargs in Deno, developers can build user interfaces for command-line applications, allowing text searches in specified directories.
- Deno provides built-in functions such as
Deno.readDir
for listing files andDeno.readTextFile
for reading file contents, thus simplifying file system interaction without additional imports. - You can use Deno's path module to efficiently manage file paths, which includes functions such as
path.join
to connect file paths. - Deno scripts require explicit permission flags, such as
–allow-read
or–allow-write
to perform file system operations, which enhances security by controlling script functions. - Developers can use
deno compile
to compile Deno scripts into separate executables, simplifying distribution and execution by encapsulating the necessary permissions.
Installation Deno
We assume that you have Deno running on your local machine. You can check out the Deno website or the previous article for more detailed installation instructions and information on how to add Deno support to your editor.
At the time of writing, the latest stable version of Deno is 1.10.2, which is the version I use in this article.
For reference, you can find the full code for this article on GitHub.
Set new commands with Yargs
As in the previous post, we will use Yargs to build interfaces that users can use to execute our tools. Let's create index.ts and fill it with the following:
import yargs from "https://deno.land/x/yargs@v17.0.1-deno/deno.ts"; interface Yargs<argvreturntype></argvreturntype> { describe: (param: string, description: string) => Yargs<argvreturntype>; </argvreturntype> demandOption: (required: string[]) => Yargs<argvreturntype>; </argvreturntype> argv: ArgvReturnType; } interface UserArguments { text: string; } const userArguments: UserArguments = (yargs(Deno.args) as unknown as Yargs<userarguments>) </userarguments> .describe("text", "the text to search for within the current directory") .demandOption(["text"]) .argv; console.log(userArguments);
There are a lot to point out here:
- We install Yargs by pointing to the path in the Deno repository. I explicitly use the exact version number to make sure we always get that version so we don't use any latest versions when the script is running.
- At the time of writing, Deno TypeScript has not had a good experience with Yargs, so I created my own interface and used it to provide some type safety.
- UserArguments contains all the input we will request from the user. Currently, we only ask for text input, but in the future we can expand it to provide a list of files to search, rather than assuming the current directory.
We can run it with deno run index.ts and see our Yargs output:
import yargs from "https://deno.land/x/yargs@v17.0.1-deno/deno.ts"; interface Yargs<argvreturntype></argvreturntype> { describe: (param: string, description: string) => Yargs<argvreturntype>; </argvreturntype> demandOption: (required: string[]) => Yargs<argvreturntype>; </argvreturntype> argv: ArgvReturnType; } interface UserArguments { text: string; } const userArguments: UserArguments = (yargs(Deno.args) as unknown as Yargs<userarguments>) </userarguments> .describe("text", "the text to search for within the current directory") .demandOption(["text"]) .argv; console.log(userArguments);
It's time to start implementing it!
List the file
Before we start searching for text in a given file, we need to generate a directory and list of files to search for. Deno provides Deno.readdir, which is part of the "built-in" library, which means you don't have to import it. It is available in the global namespace.
Deno.readdir is asynchronous and returns a list of files and folders in the current directory. It returns these items as AsyncIterator, which means we have to use for await ... of loop to get the result:
$ deno run index.ts Check file:///home/jack/git/deno-file-search/index.ts Options: --help Show help [boolean] --version Show version number [boolean] --text the text to search for within the current directory [required] Missing required argument: text
This code will read and record each result from the current working directory (provided by Deno.cwd()). However, if you try to run the script now, you will receive an error:
for await (const fileOrFolder of Deno.readDir(Deno.cwd())) { console.log(fileOrFolder); }
Remember that Deno requires that all scripts explicitly obtain permissions to read from the file system. In our case, the --allow-read
flag will enable our code to run:
$ deno run index.ts --text='foo' error: Uncaught PermissionDenied: Requires read access to <cwd>, run again with the --allow-read flag </cwd>for await (const fileOrFolder of Deno.readDir(Deno.cwd())) { ^ at deno:core/core.js:86:46 at unwrapOpResult (deno:core/core.js:106:13) at Object.opSync (deno:core/core.js:120:12) at Object.cwd (deno:runtime/js/30_fs.js:57:17) at file:///home/jack/git/deno-file-search/index.ts:19:52
In this case, I run the script in the directory of the build tool, so it finds the TS source code, the .git repository, and the .vscode folder. Let's start writing some functions to recursively navigate this structure, because we need to find all the files in the directory, not just the top-level files. Additionally, we can add some common ignores. I don't think anyone would want the script to search the entire .git folder!
In the following code, we create the getFilesList function, which takes a directory and returns all files in that directory. If a directory is encountered, it will recursively call itself to find any nested files and return the result:
~/$ deno run --allow-read index.ts --text='foo' { name: ".git", isFile: false, isDirectory: true, isSymlink: false } { name: ".vscode", isFile: false, isDirectory: true, isSymlink: false } { name: "index.ts", isFile: true, isDirectory: false, isSymlink: false }
Then we can use it like this:
const IGNORED_DIRECTORIES = new Set([".git"]); async function getFilesList( directory: string, ): Promise<string[]> { const foundFiles: string[] = []; for await (const fileOrFolder of Deno.readDir(directory)) { if (fileOrFolder.isDirectory) { if (IGNORED_DIRECTORIES.has(fileOrFolder.name)) { // Skip this folder, it's in the ignore list. continue; } // If it's not ignored, recurse and search this folder for files. const nestedFiles = await getFilesList( path.join(directory, fileOrFolder.name), ); foundFiles.push(...nestedFiles); } else { // We found a file, so store it. foundFiles.push(path.join(directory, fileOrFolder.name)); } } return foundFiles; }
We also get some output that looks good:
const files = await getFilesList(Deno.cwd()); console.log(files);
Using the path module
We can now combine file paths using template strings as follows:
$ deno run --allow-read index.ts --text='foo' [ "/home/jack/git/deno-file-search/.vscode/settings.json", "/home/jack/git/deno-file-search/index.ts" ]
But this would be better with Deno's path module. This module is one of the modules Deno offers as part of its standard library (very similar to Node using its path module), and if you have used Node's path module, the code looks very similar. At the time of writing, the latest standard library version provided by Deno is 0.97.0, we import the path module from the mod.ts file:
import yargs from "https://deno.land/x/yargs@v17.0.1-deno/deno.ts"; interface Yargs<argvreturntype></argvreturntype> { describe: (param: string, description: string) => Yargs<argvreturntype>; </argvreturntype> demandOption: (required: string[]) => Yargs<argvreturntype>; </argvreturntype> argv: ArgvReturnType; } interface UserArguments { text: string; } const userArguments: UserArguments = (yargs(Deno.args) as unknown as Yargs<userarguments>) </userarguments> .describe("text", "the text to search for within the current directory") .demandOption(["text"]) .argv; console.log(userArguments);
mod.ts is always the entry point when importing Deno's standard modules. The documentation for this module is located on the Deno website and lists path.join, which will take multiple paths and join them into one path. Let's import and use the functions instead of combining them manually:
...(The rest of the code is omitted here because it is repeated with the original text and has been modified and optimized in the previous output.)
...(The rest of the code is omitted because it's repetitive from the original and has already been modified and optimized in the previous output.)
: : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :The above is the detailed content of Working with the File System in Deno. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

Java and JavaScript are different programming languages, each suitable for different application scenarios. Java is used for large enterprise and mobile application development, while JavaScript is mainly used for web page development.

JavaScriptcommentsareessentialformaintaining,reading,andguidingcodeexecution.1)Single-linecommentsareusedforquickexplanations.2)Multi-linecommentsexplaincomplexlogicorprovidedetaileddocumentation.3)Inlinecommentsclarifyspecificpartsofcode.Bestpractic

The following points should be noted when processing dates and time in JavaScript: 1. There are many ways to create Date objects. It is recommended to use ISO format strings to ensure compatibility; 2. Get and set time information can be obtained and set methods, and note that the month starts from 0; 3. Manually formatting dates requires strings, and third-party libraries can also be used; 4. It is recommended to use libraries that support time zones, such as Luxon. Mastering these key points can effectively avoid common mistakes.

PlacingtagsatthebottomofablogpostorwebpageservespracticalpurposesforSEO,userexperience,anddesign.1.IthelpswithSEObyallowingsearchenginestoaccesskeyword-relevanttagswithoutclutteringthemaincontent.2.Itimprovesuserexperiencebykeepingthefocusonthearticl

JavaScriptispreferredforwebdevelopment,whileJavaisbetterforlarge-scalebackendsystemsandAndroidapps.1)JavaScriptexcelsincreatinginteractivewebexperienceswithitsdynamicnatureandDOMmanipulation.2)Javaoffersstrongtypingandobject-orientedfeatures,idealfor

Event capture and bubble are two stages of event propagation in DOM. Capture is from the top layer to the target element, and bubble is from the target element to the top layer. 1. Event capture is implemented by setting the useCapture parameter of addEventListener to true; 2. Event bubble is the default behavior, useCapture is set to false or omitted; 3. Event propagation can be used to prevent event propagation; 4. Event bubbling supports event delegation to improve dynamic content processing efficiency; 5. Capture can be used to intercept events in advance, such as logging or error processing. Understanding these two phases helps to accurately control the timing and how JavaScript responds to user operations.

JavaScripthassevenfundamentaldatatypes:number,string,boolean,undefined,null,object,andsymbol.1)Numbersuseadouble-precisionformat,usefulforwidevaluerangesbutbecautiouswithfloating-pointarithmetic.2)Stringsareimmutable,useefficientconcatenationmethodsf

If JavaScript applications load slowly and have poor performance, the problem is that the payload is too large. Solutions include: 1. Use code splitting (CodeSplitting), split the large bundle into multiple small files through React.lazy() or build tools, and load it as needed to reduce the first download; 2. Remove unused code (TreeShaking), use the ES6 module mechanism to clear "dead code" to ensure that the introduced libraries support this feature; 3. Compress and merge resource files, enable Gzip/Brotli and Terser to compress JS, reasonably merge files and optimize static resources; 4. Replace heavy-duty dependencies and choose lightweight libraries such as day.js and fetch
