asljs-locator 0.0.0-stage → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md ADDED
@@ -0,0 +1,51 @@
1
+ # Permissive No-Derivatives License 1.0
2
+
3
+ Copyright (c) 2026 Alexandrite Software Ltd.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software (the "Software") to:
7
+
8
+ 1. Use the Software for any purpose, including commercial purposes.
9
+ 2. Copy and redistribute the Software, including as part of another application,
10
+ library, or package.
11
+ 3. Modify the Software for private or internal use.
12
+
13
+ Subject to the following conditions:
14
+
15
+ ## 1. No Distribution of Modified Versions
16
+
17
+ Modified versions of the Software, or substantial portions thereof, must not be
18
+ distributed without prior written permission from the copyright holder.
19
+
20
+ Routine build transformations, including minification, transpilation, and
21
+ bundling, are permitted for distribution, provided they do not intentionally
22
+ alter the Software's functionality.
23
+
24
+ ## 2. Licence and Copyright Preservation
25
+
26
+ All distributed copies of the Software must retain this copyright notice and
27
+ licence.
28
+
29
+ The Software itself, including copies incorporated into other applications,
30
+ libraries, or packages, remains subject to this licence.
31
+
32
+ The Software must not be sublicensed or redistributed under a different licence.
33
+
34
+ ## 3. Use in Other Software
35
+
36
+ Applications and libraries that merely use, import, link to, or bundle the
37
+ Software are not considered modified versions of the Software and may be
38
+ distributed under any licence.
39
+
40
+ Such use, incorporation, or bundling does not grant permission to relicense the
41
+ Software or distribute modified versions of it.
42
+
43
+ ### 4. No Warranty
44
+
45
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
46
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
47
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
48
+
49
+ IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR
50
+ OTHER LIABILITY ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR ITS
51
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,100 @@
1
- # Temporary Holding Version
1
+ # locator
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ > Part of [Alexandrite Software Library][1] – a set of high‑quality, performant
4
+ > JavaScript libraries for everyday use.
5
+
6
+ ## Overview
7
+
8
+ `asljs-locator` locates files by glob patterns, exclusions and filters such as
9
+ `.gitignore`.
10
+
11
+ A location says where a set of files lives: the patterns that match them, the
12
+ patterns that take them away again, and the filters that drop whatever should
13
+ never have been listed. `.gitignore` is one of those filters, so a tool can
14
+ honour it without reimplementing it.
15
+
16
+ A pattern beginning with `/` resolves against the root the resolver was built
17
+ with. Any other pattern resolves against the base path given to the call. That
18
+ pair is what lets one vocabulary describe both a repository-wide location and a
19
+ location relative to the file that declared it.
20
+
21
+ An absolute path is a pattern where it is, inside the root or not:
22
+ `C:/notes/*.md` always, and `/tmp/notes/*.md` when the root has no `tmp` and the
23
+ file system root has one. A pattern beginning with `/` whose first segment the
24
+ root has, or which begins with a glob, such as `/docs/**` or `/**/*.md`, stays
25
+ from the root.
26
+
27
+ ## Scope
28
+
29
+ Finding paths, and answering whether a path belongs to a location. Reading the
30
+ files it finds is the caller's business.
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ npm install asljs-locator
36
+ ```
37
+
38
+ NPM Package: [asljs-locator][NPM]
39
+
40
+ ## Usage
41
+
42
+ ```js
43
+ import {
44
+ LocationResolver
45
+ } from 'asljs-locator';
46
+ import {
47
+ NullLogger
48
+ } from 'asljs-logging';
49
+
50
+ const resolver = new LocationResolver(new NullLogger(), process.cwd());
51
+
52
+ const files = await resolver.resolve(process.cwd(), {
53
+ patterns: ['docs/**/*.md'],
54
+ exclude: ['docs/drafts/**'],
55
+ filters: [{ name: 'GitIgnore' }]
56
+ });
57
+ ```
58
+
59
+ `resolve` returns absolute paths, deduplicated and sorted. Give it one location
60
+ or several; several are merged.
61
+
62
+ `check` answers the same question for a single path without walking the tree,
63
+ which is what makes it usable per file:
64
+
65
+ ```js
66
+ const belongs = await resolver.check(
67
+ '/repo/docs/guide.md',
68
+ '/repo',
69
+ { pattern: 'docs/**/*.md' }
70
+ );
71
+ ```
72
+
73
+ Patterns match files only. A pattern ending with `/` would name folders and
74
+ throws; to treat a folder as an item, point at a file inside it, e.g.
75
+ `packages/*/package.json`.
76
+
77
+ Two path helpers come with it: `toPosixPath(path)`, the path with forward
78
+ slashes, and `isInside(folder, target, { orSame? })`, whether `target` is
79
+ `folder` or below it; with `orSame: false`, only below it.
80
+
81
+ ## Further reading
82
+
83
+ - [Architecture][2] for where this sits among the packages.
84
+
85
+ Questions and bugs: [asljs/issues][ISS].
86
+
87
+ ## Related packages
88
+
89
+ - [asljs-logging][3] provides the logger the resolver traces through.
90
+
91
+ ## License
92
+
93
+ MIT License. See [LICENSE][LIC] for details.
94
+
95
+ [1]: https://github.com/AlexandriteSoftware/asljs
96
+ [2]: ../../docs/Architecture.md
97
+ [3]: ../logging/README.md
98
+ [ISS]: https://github.com/AlexandriteSoftware/asljs/issues
99
+ [LIC]: LICENSE.md
100
+ [NPM]: https://www.npmjs.com/package/asljs-locator
@@ -0,0 +1,17 @@
1
+ import { Logger } from 'asljs-logging';
2
+ /**
3
+ * Whether a path is ignored by a `.gitignore`.
4
+ *
5
+ * Matchers are loaded from the directory of the path being tested and every
6
+ * directory above it, because a nested `.gitignore` applies to its own subtree
7
+ * and git reads them all. Each directory is read once.
8
+ */
9
+ export declare class GitIgnore {
10
+ private logger;
11
+ private matchers;
12
+ private visitedPaths;
13
+ constructor(logger: Logger);
14
+ isIgnored(targetPath: string): boolean;
15
+ filter(paths: string[]): string[];
16
+ loadMatchers(directoryPath: string): void;
17
+ }
@@ -0,0 +1,81 @@
1
+ import ignore from 'ignore';
2
+ import { readFileSync, statSync } from 'node:fs';
3
+ import path from 'node:path';
4
+ import { toPosixPath } from './paths.js';
5
+ /**
6
+ * Whether a path is ignored by a `.gitignore`.
7
+ *
8
+ * Matchers are loaded from the directory of the path being tested and every
9
+ * directory above it, because a nested `.gitignore` applies to its own subtree
10
+ * and git reads them all. Each directory is read once.
11
+ */
12
+ export class GitIgnore {
13
+ logger;
14
+ matchers;
15
+ visitedPaths;
16
+ constructor(logger) {
17
+ this.logger = logger;
18
+ this.matchers = [];
19
+ this.visitedPaths = new Set();
20
+ }
21
+ isIgnored(targetPath) {
22
+ if (!path.isAbsolute(targetPath)) {
23
+ throw new Error(`Path must be absolute: ${targetPath}`);
24
+ }
25
+ const isDirectory = targetPath.endsWith(path.sep);
26
+ const normalisedPath = path.normalize(targetPath);
27
+ if (isDirectory) {
28
+ this.loadMatchers(normalisedPath);
29
+ }
30
+ else {
31
+ this.loadMatchers(path.dirname(normalisedPath));
32
+ }
33
+ for (const matcher of this.matchers) {
34
+ const relativePath = toPosixPath(path.relative(matcher.path, normalisedPath));
35
+ if (relativePath === ''
36
+ || relativePath.startsWith('../')) {
37
+ continue;
38
+ }
39
+ const testRelativePath = isDirectory
40
+ ? relativePath + '/'
41
+ : relativePath;
42
+ if (matcher.matcher.ignores(testRelativePath)) {
43
+ return true;
44
+ }
45
+ }
46
+ return false;
47
+ }
48
+ filter(paths) {
49
+ return paths.filter(filePath => !this.isIgnored(filePath));
50
+ }
51
+ loadMatchers(directoryPath) {
52
+ if (this.visitedPaths.has(directoryPath)) {
53
+ return;
54
+ }
55
+ this.visitedPaths
56
+ .add(directoryPath);
57
+ const gitIgnorePath = path.join(directoryPath, '.gitignore');
58
+ let gitIgnoreExists = false;
59
+ try {
60
+ statSync(gitIgnorePath);
61
+ gitIgnoreExists = true;
62
+ }
63
+ catch (err) {
64
+ const code = err.code;
65
+ if (code !== 'ENOENT') {
66
+ throw err;
67
+ }
68
+ }
69
+ if (gitIgnoreExists) {
70
+ const gitIgnoreContent = readFileSync(gitIgnorePath, 'utf8');
71
+ const matcher = ignore()
72
+ .add(gitIgnoreContent);
73
+ this.matchers.push({ path: directoryPath,
74
+ matcher });
75
+ }
76
+ const parentPath = path.dirname(directoryPath);
77
+ if (parentPath !== directoryPath) {
78
+ this.loadMatchers(parentPath);
79
+ }
80
+ }
81
+ }
@@ -0,0 +1,3 @@
1
+ export { GitIgnore } from './git-ignore.js';
2
+ export { LocationResolver, toPatterns, type Location, type LocationFilter } from './location.js';
3
+ export { isInside, toPosixPath } from './paths.js';
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { GitIgnore } from './git-ignore.js';
2
+ export { LocationResolver, toPatterns } from './location.js';
3
+ export { isInside, toPosixPath } from './paths.js';
@@ -0,0 +1,71 @@
1
+ import { type Logger } from 'asljs-logging';
2
+ /**
3
+ * A named filter applied to the matches, rather than a pattern.
4
+ *
5
+ * `GitIgnore` is the only one implemented: it drops whatever git would ignore.
6
+ */
7
+ export interface LocationFilter {
8
+ name: string;
9
+ }
10
+ /**
11
+ * Where a set of files lives.
12
+ *
13
+ * A pattern beginning with `/` is resolved against the root the resolver was
14
+ * built with; any other pattern is resolved against the base path passed to
15
+ * the call. That is what lets a definition name a repository-wide location and
16
+ * a location relative to itself in the same vocabulary.
17
+ *
18
+ * Give either `pattern` for one or `patterns` for several; both are accepted
19
+ * and read as one list.
20
+ */
21
+ export interface Location {
22
+ pattern?: string;
23
+ patterns?: string[];
24
+ exclude?: string[];
25
+ filters?: LocationFilter[];
26
+ }
27
+ /** The patterns of a location, however they were given. */
28
+ export declare function toPatterns(location: Location): string[];
29
+ export declare class LocationResolver {
30
+ private logger;
31
+ private rootPath;
32
+ private gitIgnore;
33
+ constructor(logger: Logger, rootPath: string);
34
+ /**
35
+ * Every path the locations match, deduplicated and sorted.
36
+ */
37
+ resolve(basePath: string, location: Location | readonly Location[]): Promise<string[]>;
38
+ /**
39
+ * Whether the target path belongs to any of the locations.
40
+ *
41
+ * This answers the question without walking the filesystem, which is what
42
+ * makes it usable per file.
43
+ */
44
+ check(targetPath: string, basePath: string, location: Location | readonly Location[]): Promise<boolean>;
45
+ private resolveOne;
46
+ private checkOne;
47
+ /**
48
+ * How a pattern resolves: `absolute`, a path of the file system, such as
49
+ * `/tmp/notes/*.md` or `C:/notes/*.md`; `root`, from the root, such as
50
+ * `/docs/**`; or `base`, from the base path.
51
+ *
52
+ * A pattern beginning with `/` is from the root, unless its first segment
53
+ * is no glob, the root has no entry of that name, and the file system root
54
+ * has one: `/tmp/x.md`, given under a root without a `tmp`, names the file
55
+ * where it is.
56
+ */
57
+ private kindOf;
58
+ /**
59
+ * The absolute paths the patterns match.
60
+ *
61
+ * An absolute pattern is expanded where it is, one beginning with `/` from
62
+ * the root, the rest from the base path, so one call can carry every kind;
63
+ * see `kindOf`.
64
+ *
65
+ * Dotfiles are matched, because `check` matches them and the two have to
66
+ * agree: without it a path such as `.remarkrc.mjs` would be reported as
67
+ * belonging to a location that never finds it.
68
+ */
69
+ private expand;
70
+ private applyFilters;
71
+ }
@@ -0,0 +1,205 @@
1
+ import { glob } from 'glob';
2
+ import { minimatch } from 'minimatch';
3
+ import { existsSync } from 'node:fs';
4
+ import path from 'node:path';
5
+ import { GitIgnore } from './git-ignore.js';
6
+ import { toPosixPath } from './paths.js';
7
+ /** The patterns of a location, however they were given. */
8
+ export function toPatterns(location) {
9
+ const patterns = [...location.pattern === undefined
10
+ ? []
11
+ : [location.pattern],
12
+ ...location.patterns
13
+ ?? []];
14
+ if (patterns.length === 0) {
15
+ throw new Error('A location needs a pattern or patterns.');
16
+ }
17
+ return patterns;
18
+ }
19
+ /**
20
+ * Patterns match files only. A pattern ending with `/` would name folders,
21
+ * which `resolve` and `check` cannot treat alike, so it is refused.
22
+ */
23
+ function assertFilePatterns(patterns) {
24
+ const folderPattern = patterns.find(pattern => pattern.endsWith('/'));
25
+ if (folderPattern !== undefined) {
26
+ throw new Error(`Folder patterns are not supported: "${folderPattern}". Point the pattern at a file, e.g. "${folderPattern}package.json".`);
27
+ }
28
+ }
29
+ function toLocations(location) {
30
+ return Array.isArray(location)
31
+ ? location
32
+ : [location];
33
+ }
34
+ export class LocationResolver {
35
+ logger;
36
+ rootPath;
37
+ gitIgnore;
38
+ constructor(logger, rootPath) {
39
+ this.logger = logger;
40
+ this.rootPath =
41
+ path.normalize(path.resolve(rootPath));
42
+ this.gitIgnore =
43
+ new GitIgnore(this.logger);
44
+ }
45
+ /**
46
+ * Every path the locations match, deduplicated and sorted.
47
+ */
48
+ async resolve(basePath, location) {
49
+ const results = [];
50
+ for (const one of toLocations(location)) {
51
+ const resolved = await this.resolveOne(basePath, one);
52
+ results.push(...resolved);
53
+ }
54
+ const unique = [...new Set(results)];
55
+ unique.sort((a, b) => a.localeCompare(b));
56
+ return unique;
57
+ }
58
+ /**
59
+ * Whether the target path belongs to any of the locations.
60
+ *
61
+ * This answers the question without walking the filesystem, which is what
62
+ * makes it usable per file.
63
+ */
64
+ async check(targetPath, basePath, location) {
65
+ for (const one of toLocations(location)) {
66
+ const matched = await this.checkOne(targetPath, basePath, one);
67
+ if (matched) {
68
+ return true;
69
+ }
70
+ }
71
+ return false;
72
+ }
73
+ async resolveOne(basePath, location) {
74
+ const patterns = toPatterns(location);
75
+ const exclude = location.exclude
76
+ ?? [];
77
+ const filters = location.filters
78
+ ?? [];
79
+ this.logger.trace('LocationResolver.resolve(%s, %s)', basePath, JSON.stringify(location));
80
+ const normalisedBasePath = path.normalize(path.resolve(basePath));
81
+ assertFilePatterns([...patterns,
82
+ ...exclude]);
83
+ const matches = new Set(await this.expand(patterns, normalisedBasePath));
84
+ for (const excluded of await this.expand(exclude, normalisedBasePath)) {
85
+ matches.delete(excluded);
86
+ }
87
+ const result = this.applyFilters([...matches], filters);
88
+ result.sort((a, b) => a.localeCompare(b));
89
+ this.logger.trace('LocationResolver.resolve() => %d matches', result.length);
90
+ return result;
91
+ }
92
+ async checkOne(targetPath, basePath, location) {
93
+ const patterns = toPatterns(location);
94
+ const exclude = location.exclude
95
+ ?? [];
96
+ const filters = location.filters
97
+ ?? [];
98
+ assertFilePatterns([...patterns,
99
+ ...exclude]);
100
+ const normalisedTargetPath = path.normalize(path.resolve(targetPath));
101
+ const normalisedBasePath = path.normalize(path.resolve(basePath));
102
+ const matchesPattern = (pattern) => {
103
+ const kind = this.kindOf(pattern);
104
+ if (kind === 'absolute') {
105
+ return minimatch(toPosixPath(normalisedTargetPath), toPosixPath(pattern), { dot: true });
106
+ }
107
+ const relativePath = path.relative(kind === 'root'
108
+ ? this.rootPath
109
+ : normalisedBasePath, normalisedTargetPath);
110
+ return minimatch(relativePath, kind === 'root'
111
+ ? pattern.slice(1)
112
+ : pattern, { dot: true });
113
+ };
114
+ if (!patterns.some(matchesPattern)) {
115
+ return false;
116
+ }
117
+ if (exclude.some(matchesPattern)) {
118
+ return false;
119
+ }
120
+ const result = this.applyFilters([normalisedTargetPath], filters);
121
+ return result.length > 0;
122
+ }
123
+ /**
124
+ * How a pattern resolves: `absolute`, a path of the file system, such as
125
+ * `/tmp/notes/*.md` or `C:/notes/*.md`; `root`, from the root, such as
126
+ * `/docs/**`; or `base`, from the base path.
127
+ *
128
+ * A pattern beginning with `/` is from the root, unless its first segment
129
+ * is no glob, the root has no entry of that name, and the file system root
130
+ * has one: `/tmp/x.md`, given under a root without a `tmp`, names the file
131
+ * where it is.
132
+ */
133
+ kindOf(pattern) {
134
+ if (!pattern.startsWith('/')) {
135
+ return path.isAbsolute(pattern)
136
+ ? 'absolute'
137
+ : 'base';
138
+ }
139
+ const first = pattern
140
+ .slice(1)
141
+ .split('/')[0];
142
+ return first !== ''
143
+ && !/[*?[\]{}()!+@]/.test(first)
144
+ && !existsSync(path.join(this.rootPath, first))
145
+ && existsSync(path.join(path.parse(this.rootPath).root, first))
146
+ ? 'absolute'
147
+ : 'root';
148
+ }
149
+ /**
150
+ * The absolute paths the patterns match.
151
+ *
152
+ * An absolute pattern is expanded where it is, one beginning with `/` from
153
+ * the root, the rest from the base path, so one call can carry every kind;
154
+ * see `kindOf`.
155
+ *
156
+ * Dotfiles are matched, because `check` matches them and the two have to
157
+ * agree: without it a path such as `.remarkrc.mjs` would be reported as
158
+ * belonging to a location that never finds it.
159
+ */
160
+ async expand(patterns, basePath) {
161
+ const matches = [];
162
+ const absolutePatterns = patterns
163
+ .filter(pattern => this.kindOf(pattern)
164
+ === 'absolute')
165
+ .map(pattern => toPosixPath(pattern));
166
+ if (absolutePatterns.length > 0) {
167
+ matches.push(...await glob(absolutePatterns, { absolute: true,
168
+ dot: true,
169
+ nodir: true }));
170
+ }
171
+ const rootPatterns = patterns
172
+ .filter(pattern => this.kindOf(pattern)
173
+ === 'root')
174
+ .map(pattern => pattern.slice(1));
175
+ if (rootPatterns.length > 0) {
176
+ matches.push(...await glob(rootPatterns, { cwd: this.rootPath,
177
+ absolute: true,
178
+ dot: true,
179
+ nodir: true }));
180
+ }
181
+ const basePatterns = patterns.filter(pattern => this.kindOf(pattern)
182
+ === 'base');
183
+ if (basePatterns.length > 0) {
184
+ matches.push(...await glob(basePatterns, { cwd: basePath,
185
+ absolute: true,
186
+ dot: true,
187
+ nodir: true }));
188
+ }
189
+ return matches;
190
+ }
191
+ applyFilters(paths, filters) {
192
+ let result = paths;
193
+ for (const filter of filters) {
194
+ switch (filter.name) {
195
+ case 'GitIgnore':
196
+ result =
197
+ this.gitIgnore.filter(result);
198
+ break;
199
+ default:
200
+ throw new Error(`Unknown filter: ${filter.name}`);
201
+ }
202
+ }
203
+ return result;
204
+ }
205
+ }
@@ -0,0 +1,9 @@
1
+ /** A path with forward slashes, which is what glob and .gitignore expect. */
2
+ export declare function toPosixPath(filePath: string): string;
3
+ /**
4
+ * Whether `target` is inside `folder`, or is `folder` itself; with
5
+ * `orSame: false`, only inside it.
6
+ */
7
+ export declare function isInside(folder: string, target: string, options?: {
8
+ orSame?: boolean;
9
+ }): boolean;
package/dist/paths.js ADDED
@@ -0,0 +1,18 @@
1
+ import path from 'node:path';
2
+ /** A path with forward slashes, which is what glob and .gitignore expect. */
3
+ export function toPosixPath(filePath) {
4
+ return filePath.replaceAll('\\', '/');
5
+ }
6
+ /**
7
+ * Whether `target` is inside `folder`, or is `folder` itself; with
8
+ * `orSame: false`, only inside it.
9
+ */
10
+ export function isInside(folder, target, options = {}) {
11
+ const relative = path.relative(path.resolve(folder), path.resolve(target));
12
+ if (relative === '') {
13
+ return options.orSame !== false;
14
+ }
15
+ return relative !== '..'
16
+ && !relative.startsWith(`..${path.sep}`)
17
+ && !path.isAbsolute(relative);
18
+ }
package/package.json CHANGED
@@ -1,6 +1,66 @@
1
1
  {
2
2
  "name": "asljs-locator",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.2",
4
+ "description": "Locates files by glob patterns, exclusions and filters such as .gitignore.",
5
+ "type": "module",
6
+ "asljs": {
7
+ "type": "lib"
8
+ },
9
+ "main": "dist/index.js",
10
+ "types": "dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "default": "./dist/index.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist/**",
19
+ "README.md",
20
+ "LICENSE.md",
21
+ "docs/**"
22
+ ],
23
+ "scripts": {
24
+ "flint": "toolkit flint",
25
+ "clean": "toolkit clean",
26
+ "build": "npm run codegen --if-present && tsc -p tsconfig.build.json",
27
+ "build:dist": "npm run codegen --if-present && tsc -p tsconfig.dist.json",
28
+ "typecheck": "npm run codegen --if-present && tsc -p tsconfig.build.json --noEmit",
29
+ "guard:clean-git": "toolkit ensure-clean-working-directory",
30
+ "prepack": "npm run clean && npm run build:dist && npm run build && npm run test && npm run guard:clean-git",
31
+ "postpublish": "toolkit tag-release-revision",
32
+ "test": "node --test --enable-source-maps \"build/**/*.test.js\"",
33
+ "test:watch": "node --watch --test \"build/**/*.test.js\"",
34
+ "coverage": "npm run build && node --test --experimental-test-coverage --enable-source-maps --test-coverage-exclude=\"**/*.test.js\" \"build/**/*.test.js\"",
35
+ "release:patch": "toolkit release-patch",
36
+ "all": "npm run clean && npm run build:dist && npm run flint && npm run typecheck && npm run build && npm run test"
37
+ },
38
+ "keywords": [
39
+ "glob",
40
+ "gitignore",
41
+ "files",
42
+ "nodejs",
43
+ "locator"
44
+ ],
45
+ "homepage": "https://github.com/AlexandriteSoftware/asljs#readme",
46
+ "bugs": {
47
+ "url": "https://github.com/AlexandriteSoftware/asljs/issues"
48
+ },
49
+ "repository": {
50
+ "type": "git",
51
+ "url": "git+https://github.com/AlexandriteSoftware/asljs.git"
52
+ },
53
+ "author": "\"Alex Netkachov\" <alex.netkachov@gmail.com>",
54
+ "license": "SEE LICENSE IN LICENSE.md",
55
+ "dependencies": {
56
+ "asljs-logging": "^0.1.1",
57
+ "glob": "^13.0.6",
58
+ "ignore": "^7.0.6",
59
+ "minimatch": "^10.2.6"
60
+ },
61
+ "devDependencies": {
62
+ "asljs-testing": "^0.1.0",
63
+ "asljs-tmpdir": "^0.1.13",
64
+ "asljs-toolkit": "^0.1.0"
65
+ }
66
+ }