@markuplint/create-rule 5.0.0-rc.4 → 5.0.0-rc.5
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/CHANGELOG.md +10 -0
- package/README.md +2 -2
- package/lib/cli.js +23 -45
- package/lib/create-rule-helper-error.d.ts +0 -5
- package/lib/create-rule-helper-error.js +0 -5
- package/lib/create-rule-helper.d.ts +0 -7
- package/lib/create-rule-helper.js +0 -7
- package/lib/create-rule-package.d.ts +0 -11
- package/lib/create-rule-package.js +0 -11
- package/lib/create-rule-to-core.d.ts +0 -19
- package/lib/create-rule-to-core.js +0 -22
- package/lib/create-rule-to-project.d.ts +0 -8
- package/lib/create-rule-to-project.js +0 -8
- package/lib/fs-exists.d.ts +0 -9
- package/lib/fs-exists.js +0 -9
- package/lib/glob.d.ts +0 -5
- package/lib/glob.js +0 -5
- package/lib/install-scaffold.d.ts +0 -14
- package/lib/install-scaffold.js +0 -14
- package/lib/is-markuplint-repo.d.ts +1 -5
- package/lib/is-markuplint-repo.js +1 -5
- package/lib/read-package-json.d.ts +0 -7
- package/lib/read-package-json.js +0 -7
- package/lib/search-core-repository.d.ts +0 -8
- package/lib/search-core-repository.js +0 -8
- package/lib/transfer.d.ts +3 -17
- package/lib/transfer.js +8 -12
- package/lib/types.d.ts +2 -42
- package/package.json +6 -6
- package/scaffold/core/meta.ts +1 -1
- package/scaffold/package/tsconfig.json +5 -3
- package/ARCHITECTURE.ja.md +0 -194
- package/ARCHITECTURE.md +0 -194
- package/SKILL.md +0 -74
- package/docs/maintenance.ja.md +0 -135
- package/docs/maintenance.md +0 -135
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [5.0.0-rc.5](https://github.com/markuplint/markuplint/compare/v5.0.0-rc.4...v5.0.0-rc.5) (2026-08-28)
|
|
7
|
+
|
|
8
|
+
### Code Refactoring
|
|
9
|
+
|
|
10
|
+
- **rules:** redesign v5 rule system — naming, splits, specConformance ([#3989](https://github.com/markuplint/markuplint/issues/3989)) ([e925565](https://github.com/markuplint/markuplint/commit/e925565ce537848d7d1573369723cbce724a841b)), closes [#4](https://github.com/markuplint/markuplint/issues/4) [#aside-conditional-role-mapping-aria-13](https://github.com/markuplint/markuplint/issues/aside-conditional-role-mapping-aria-13)
|
|
11
|
+
|
|
12
|
+
### BREAKING CHANGES
|
|
13
|
+
|
|
14
|
+
- **rules:** with no alias coverage.
|
|
15
|
+
|
|
6
16
|
# [5.0.0-rc.4](https://github.com/markuplint/markuplint/compare/v5.0.0-rc.3...v5.0.0-rc.4) (2026-04-19)
|
|
7
17
|
|
|
8
18
|
**Note:** Version bump only for package @markuplint/create-rule
|
package/README.md
CHANGED
|
@@ -50,7 +50,7 @@ $ npx @markuplint/create-rule -p project -n my-plugin -r no-empty-alt --json
|
|
|
50
50
|
| `--json` | | Output result as JSON | `false` |
|
|
51
51
|
| `--help` | `-h` | Show help message | |
|
|
52
52
|
|
|
53
|
-
Available categories: `
|
|
53
|
+
Available categories: `syntax`, `structure`, `attributes`, `references`, `forms`, `a11y`, `style`, `maintainability`, `compat`
|
|
54
54
|
|
|
55
55
|
> When contributing to core (`--purpose core`), `--lang` is always TypeScript and `--test` is always enabled regardless of the options provided.
|
|
56
56
|
|
|
@@ -73,7 +73,7 @@ The CLI asks questions in the following order:
|
|
|
73
73
|
3. **Rule name** — The kebab-case name of the rule (e.g., `no-empty-alt`)
|
|
74
74
|
4. **Core-only questions** (contribute to core only):
|
|
75
75
|
- Description
|
|
76
|
-
- Category (`
|
|
76
|
+
- Category (`syntax`, `structure`, `attributes`, `references`, `forms`, `a11y`, `style`, `maintainability`, `compat`)
|
|
77
77
|
- Severity (`error` or `warning`)
|
|
78
78
|
5. **Language** — TypeScript or JavaScript (core mode always uses TypeScript)
|
|
79
79
|
6. **Tests** — Whether to generate test files (core mode always includes tests)
|
package/lib/cli.js
CHANGED
|
@@ -4,16 +4,23 @@ import { input, installModule, select, confirm, font, header, xterm } from '@mar
|
|
|
4
4
|
import { createRuleHelper } from './create-rule-helper.js';
|
|
5
5
|
import { isMarkuplintRepo } from './is-markuplint-repo.js';
|
|
6
6
|
const KEBAB_CASE = /^[a-z][\da-z]*(?:-[a-z][\da-z]*)*$/i;
|
|
7
|
-
const CATEGORIES = [
|
|
7
|
+
const CATEGORIES = [
|
|
8
|
+
'syntax',
|
|
9
|
+
'structure',
|
|
10
|
+
'attributes',
|
|
11
|
+
'references',
|
|
12
|
+
'forms',
|
|
13
|
+
'a11y',
|
|
14
|
+
'style',
|
|
15
|
+
'maintainability',
|
|
16
|
+
'compat',
|
|
17
|
+
];
|
|
8
18
|
const SEVERITIES = ['error', 'warning'];
|
|
9
19
|
const PURPOSE_MAP = {
|
|
10
20
|
project: 'ADD_TO_PROJECT',
|
|
11
21
|
package: 'PUBLISH_AS_PACKAGE',
|
|
12
22
|
core: 'CONTRIBUTE_TO_CORE',
|
|
13
23
|
};
|
|
14
|
-
/**
|
|
15
|
-
* Icon mapping for scaffold output display, keyed by base file name.
|
|
16
|
-
*/
|
|
17
24
|
const icons = {
|
|
18
25
|
README: '📝',
|
|
19
26
|
index: '📜',
|
|
@@ -21,9 +28,6 @@ const icons = {
|
|
|
21
28
|
package: '🎁',
|
|
22
29
|
tsconfig: '💎',
|
|
23
30
|
};
|
|
24
|
-
/**
|
|
25
|
-
* Prints the CLI usage information, options, and examples to stdout.
|
|
26
|
-
*/
|
|
27
31
|
function printHelp() {
|
|
28
32
|
process.stdout.write(`
|
|
29
33
|
Usage: create-rule [options]
|
|
@@ -40,8 +44,8 @@ Options:
|
|
|
40
44
|
--no-test Skip test file generation
|
|
41
45
|
-d, --description <text> Rule description (required for core)
|
|
42
46
|
-c, --category <cat> Category (required for core):
|
|
43
|
-
|
|
44
|
-
maintainability,
|
|
47
|
+
syntax, structure, attributes, references,
|
|
48
|
+
forms, a11y, style, maintainability, compat
|
|
45
49
|
-s, --severity <level> Severity: error or warning (required for core)
|
|
46
50
|
--json Output result as JSON
|
|
47
51
|
-h, --help Show this help message
|
|
@@ -58,16 +62,11 @@ Examples:
|
|
|
58
62
|
`);
|
|
59
63
|
}
|
|
60
64
|
/**
|
|
61
|
-
* Sentinel
|
|
62
|
-
* successful early exit without using `process.exit`.
|
|
65
|
+
* Sentinel for a successful early exit on `--help`, avoiding `process.exit`.
|
|
63
66
|
*/
|
|
64
67
|
class HelpRequested {
|
|
65
68
|
code = 0;
|
|
66
69
|
}
|
|
67
|
-
/**
|
|
68
|
-
* Error thrown when CLI arguments are invalid or missing.
|
|
69
|
-
* Includes a usage hint directing users to `--help`.
|
|
70
|
-
*/
|
|
71
70
|
class UsageHintError extends Error {
|
|
72
71
|
constructor(message) {
|
|
73
72
|
super(`${message}\nRun 'create-rule --help' for usage.`);
|
|
@@ -75,10 +74,8 @@ class UsageHintError extends Error {
|
|
|
75
74
|
}
|
|
76
75
|
}
|
|
77
76
|
/**
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* @returns The parsed parameters and output format flag, or `null` when
|
|
81
|
-
* no arguments are provided (indicating interactive mode).
|
|
77
|
+
* @returns The parsed parameters, or `null` when no arguments are provided
|
|
78
|
+
* (indicating interactive mode).
|
|
82
79
|
* @throws {HelpRequested} When `--help` is passed.
|
|
83
80
|
* @throws {UsageHintError} When required options are missing or values are invalid.
|
|
84
81
|
*/
|
|
@@ -212,14 +209,6 @@ export async function createRule() {
|
|
|
212
209
|
await createRuleInteractive();
|
|
213
210
|
}
|
|
214
211
|
}
|
|
215
|
-
/**
|
|
216
|
-
* Creates a rule non-interactively from pre-validated CLI options.
|
|
217
|
-
* Runs the scaffold, prints results (or JSON), and installs dependencies.
|
|
218
|
-
*
|
|
219
|
-
* @param params - The validated rule creation parameters.
|
|
220
|
-
* @param json - When `true`, outputs the result as JSON instead of
|
|
221
|
-
* the human-readable file list.
|
|
222
|
-
*/
|
|
223
212
|
async function createRuleNonInteractive(params, json) {
|
|
224
213
|
const result = await createRuleHelper(params);
|
|
225
214
|
if (!json) {
|
|
@@ -250,13 +239,6 @@ async function createRuleNonInteractive(params, json) {
|
|
|
250
239
|
await installModule(result.devDependencies, true);
|
|
251
240
|
}
|
|
252
241
|
}
|
|
253
|
-
/**
|
|
254
|
-
* Interactive CLI wizard for creating a new markuplint rule.
|
|
255
|
-
*
|
|
256
|
-
* Guides the user through selecting a purpose, naming the plugin and rule,
|
|
257
|
-
* choosing a language, and optionally generating tests. After scaffolding,
|
|
258
|
-
* it prints the generated files and installs any required dependencies.
|
|
259
|
-
*/
|
|
260
242
|
async function createRuleInteractive() {
|
|
261
243
|
process.stdout.write(header('Create a rule'));
|
|
262
244
|
process.stdout.write('\n');
|
|
@@ -281,11 +263,15 @@ async function createRuleInteractive() {
|
|
|
281
263
|
category: await select({
|
|
282
264
|
message: 'Category:',
|
|
283
265
|
choices: [
|
|
284
|
-
{ name: '
|
|
266
|
+
{ name: 'Syntax', value: 'syntax' },
|
|
267
|
+
{ name: 'Structure', value: 'structure' },
|
|
268
|
+
{ name: 'Attributes', value: 'attributes' },
|
|
269
|
+
{ name: 'References', value: 'references' },
|
|
270
|
+
{ name: 'Forms', value: 'forms' },
|
|
285
271
|
{ name: 'Accessibility', value: 'a11y' },
|
|
286
|
-
{ name: 'Naming Convention', value: 'naming-convention' },
|
|
287
|
-
{ name: 'Maintainability', value: 'maintainability' },
|
|
288
272
|
{ name: 'Style', value: 'style' },
|
|
273
|
+
{ name: 'Maintainability', value: 'maintainability' },
|
|
274
|
+
{ name: 'Browser Compatibility', value: 'compat' },
|
|
289
275
|
],
|
|
290
276
|
}),
|
|
291
277
|
severity: await select({
|
|
@@ -318,14 +304,6 @@ async function createRuleInteractive() {
|
|
|
318
304
|
await installModule(result.devDependencies, true);
|
|
319
305
|
}
|
|
320
306
|
}
|
|
321
|
-
/**
|
|
322
|
-
* Prints a single scaffolded file entry to stdout with a check mark, icon, and file path.
|
|
323
|
-
*
|
|
324
|
-
* @param name - The plugin or module name used as a prefix.
|
|
325
|
-
* @param icon - The icon character to display next to the file name.
|
|
326
|
-
* @param title - The display title (typically the file name).
|
|
327
|
-
* @param filePath - The absolute path to the generated file.
|
|
328
|
-
*/
|
|
329
307
|
function printFile(name, icon, title, filePath) {
|
|
330
308
|
const _marker = xterm(39)('✔') + ' ';
|
|
331
309
|
const _title = (icon, title) => `${icon} ` + font.bold(`${name}/${title}`);
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Custom error class for failures that occur during rule scaffolding.
|
|
3
|
-
* Thrown when preconditions are not met (e.g., directory already exists,
|
|
4
|
-
* core options missing, or repository not found).
|
|
5
|
-
*/
|
|
6
1
|
export declare class CreateRuleHelperError extends Error {
|
|
7
2
|
name: string;
|
|
8
3
|
}
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Custom error class for failures that occur during rule scaffolding.
|
|
3
|
-
* Thrown when preconditions are not met (e.g., directory already exists,
|
|
4
|
-
* core options missing, or repository not found).
|
|
5
|
-
*/
|
|
6
1
|
export class CreateRuleHelperError extends Error {
|
|
7
2
|
name = 'CreateRuleHelperError';
|
|
8
3
|
}
|
|
@@ -1,9 +1,2 @@
|
|
|
1
1
|
import type { CreateRuleHelperParams, CreateRuleHelperResult } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Dispatches rule creation to the appropriate scaffolding function based on the
|
|
4
|
-
* specified purpose. Acts as the central entry point for programmatic rule creation.
|
|
5
|
-
*
|
|
6
|
-
* @param params - The helper parameters including purpose, plugin name, rule name, language, and options.
|
|
7
|
-
* @returns The scaffold result containing generated files and dependencies.
|
|
8
|
-
*/
|
|
9
2
|
export declare function createRuleHelper(params: CreateRuleHelperParams): Promise<CreateRuleHelperResult>;
|
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
import { createRulePackage } from './create-rule-package.js';
|
|
2
2
|
import { createRuleToCore } from './create-rule-to-core.js';
|
|
3
3
|
import { createRuleToProject } from './create-rule-to-project.js';
|
|
4
|
-
/**
|
|
5
|
-
* Dispatches rule creation to the appropriate scaffolding function based on the
|
|
6
|
-
* specified purpose. Acts as the central entry point for programmatic rule creation.
|
|
7
|
-
*
|
|
8
|
-
* @param params - The helper parameters including purpose, plugin name, rule name, language, and options.
|
|
9
|
-
* @returns The scaffold result containing generated files and dependencies.
|
|
10
|
-
*/
|
|
11
4
|
export async function createRuleHelper(params) {
|
|
12
5
|
switch (params.purpose) {
|
|
13
6
|
case 'ADD_TO_PROJECT': {
|
|
@@ -1,13 +1,2 @@
|
|
|
1
1
|
import type { CreateRuleCreatorParams, CreateRuleHelperResult } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Scaffolds a new markuplint rule as a standalone publishable npm package
|
|
4
|
-
* in the current working directory.
|
|
5
|
-
*
|
|
6
|
-
* Validates that the current directory is empty before proceeding.
|
|
7
|
-
* Generates a complete package structure including `package.json`.
|
|
8
|
-
*
|
|
9
|
-
* @param params - The rule creation parameters (plugin name, rule name, language, test preference).
|
|
10
|
-
* @returns The scaffold result containing generated files and dependencies.
|
|
11
|
-
* @throws {CreateRuleHelperError} If the current directory is not empty.
|
|
12
|
-
*/
|
|
13
2
|
export declare function createRulePackage({ pluginName, ruleName, lang, needTest, }: CreateRuleCreatorParams): Promise<CreateRuleHelperResult>;
|
|
@@ -2,17 +2,6 @@ import path from 'node:path';
|
|
|
2
2
|
import { CreateRuleHelperError } from './create-rule-helper-error.js';
|
|
3
3
|
import { glob } from './glob.js';
|
|
4
4
|
import { installScaffold } from './install-scaffold.js';
|
|
5
|
-
/**
|
|
6
|
-
* Scaffolds a new markuplint rule as a standalone publishable npm package
|
|
7
|
-
* in the current working directory.
|
|
8
|
-
*
|
|
9
|
-
* Validates that the current directory is empty before proceeding.
|
|
10
|
-
* Generates a complete package structure including `package.json`.
|
|
11
|
-
*
|
|
12
|
-
* @param params - The rule creation parameters (plugin name, rule name, language, test preference).
|
|
13
|
-
* @returns The scaffold result containing generated files and dependencies.
|
|
14
|
-
* @throws {CreateRuleHelperError} If the current directory is not empty.
|
|
15
|
-
*/
|
|
16
5
|
export async function createRulePackage({ pluginName, ruleName, lang, needTest, }) {
|
|
17
6
|
const newRuleDir = path.resolve(process.cwd(), '*');
|
|
18
7
|
const files = await glob(newRuleDir);
|
|
@@ -1,22 +1,3 @@
|
|
|
1
1
|
import type { CreateRuleCreatorParams, CreateRuleHelperResult } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Scaffolds a new rule within the markuplint core rules directory.
|
|
4
|
-
*
|
|
5
|
-
* Creates the rule in the `packages/@markuplint/rules/src/<ruleName>` directory
|
|
6
|
-
* of the monorepo. Requires core-specific parameters (description, category, severity)
|
|
7
|
-
* and always uses TypeScript with tests enabled.
|
|
8
|
-
*
|
|
9
|
-
* @param params - The rule creation parameters. The `core` property is required.
|
|
10
|
-
* @returns The scaffold result containing generated files and dependencies.
|
|
11
|
-
* @throws {CreateRuleHelperError} If core options are not defined or a rule with the same name already exists.
|
|
12
|
-
*/
|
|
13
2
|
export declare function createRuleToCore({ ruleName, core }: CreateRuleCreatorParams): Promise<CreateRuleHelperResult>;
|
|
14
|
-
/**
|
|
15
|
-
* Resolves the absolute path to the core rules source directory within the
|
|
16
|
-
* markuplint monorepo. Searches upward from the cwd for the repository root
|
|
17
|
-
* and then constructs the path to `packages/@markuplint/rules/src`.
|
|
18
|
-
*
|
|
19
|
-
* @returns The absolute path to the core rules directory.
|
|
20
|
-
* @throws {CreateRuleHelperError} If the monorepo root or the core rules directory is not found.
|
|
21
|
-
*/
|
|
22
3
|
export declare function getRulesDir(): Promise<string>;
|
|
@@ -3,21 +3,7 @@ import { CreateRuleHelperError } from './create-rule-helper-error.js';
|
|
|
3
3
|
import { fsExists } from './fs-exists.js';
|
|
4
4
|
import { installScaffold } from './install-scaffold.js';
|
|
5
5
|
import { searchCoreRepository } from './search-core-repository.js';
|
|
6
|
-
/**
|
|
7
|
-
* Relative path segments from the monorepo root to the core rules source directory.
|
|
8
|
-
*/
|
|
9
6
|
const rulesRelDir = ['packages', '@markuplint', 'rules', 'src'];
|
|
10
|
-
/**
|
|
11
|
-
* Scaffolds a new rule within the markuplint core rules directory.
|
|
12
|
-
*
|
|
13
|
-
* Creates the rule in the `packages/@markuplint/rules/src/<ruleName>` directory
|
|
14
|
-
* of the monorepo. Requires core-specific parameters (description, category, severity)
|
|
15
|
-
* and always uses TypeScript with tests enabled.
|
|
16
|
-
*
|
|
17
|
-
* @param params - The rule creation parameters. The `core` property is required.
|
|
18
|
-
* @returns The scaffold result containing generated files and dependencies.
|
|
19
|
-
* @throws {CreateRuleHelperError} If core options are not defined or a rule with the same name already exists.
|
|
20
|
-
*/
|
|
21
7
|
export async function createRuleToCore({ ruleName, core }) {
|
|
22
8
|
if (!core) {
|
|
23
9
|
throw new CreateRuleHelperError('Core options are not defined');
|
|
@@ -36,14 +22,6 @@ export async function createRuleToCore({ ruleName, core }) {
|
|
|
36
22
|
core,
|
|
37
23
|
});
|
|
38
24
|
}
|
|
39
|
-
/**
|
|
40
|
-
* Resolves the absolute path to the core rules source directory within the
|
|
41
|
-
* markuplint monorepo. Searches upward from the cwd for the repository root
|
|
42
|
-
* and then constructs the path to `packages/@markuplint/rules/src`.
|
|
43
|
-
*
|
|
44
|
-
* @returns The absolute path to the core rules directory.
|
|
45
|
-
* @throws {CreateRuleHelperError} If the monorepo root or the core rules directory is not found.
|
|
46
|
-
*/
|
|
47
25
|
export async function getRulesDir() {
|
|
48
26
|
const rootDir = await searchCoreRepository();
|
|
49
27
|
if (!rootDir) {
|
|
@@ -1,10 +1,2 @@
|
|
|
1
1
|
import type { CreateRuleCreatorParams, CreateRuleHelperResult } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Scaffolds a new markuplint rule as a local plugin directory within the
|
|
4
|
-
* current project. Creates a new directory named after the plugin in the cwd.
|
|
5
|
-
*
|
|
6
|
-
* @param params - The rule creation parameters (plugin name, rule name, language, test preference).
|
|
7
|
-
* @returns The scaffold result containing generated files and dependencies.
|
|
8
|
-
* @throws {CreateRuleHelperError} If the target plugin directory already exists.
|
|
9
|
-
*/
|
|
10
2
|
export declare function createRuleToProject({ pluginName, ruleName, lang, needTest, }: CreateRuleCreatorParams): Promise<CreateRuleHelperResult>;
|
|
@@ -2,14 +2,6 @@ import path from 'node:path';
|
|
|
2
2
|
import { CreateRuleHelperError } from './create-rule-helper-error.js';
|
|
3
3
|
import { fsExists } from './fs-exists.js';
|
|
4
4
|
import { installScaffold } from './install-scaffold.js';
|
|
5
|
-
/**
|
|
6
|
-
* Scaffolds a new markuplint rule as a local plugin directory within the
|
|
7
|
-
* current project. Creates a new directory named after the plugin in the cwd.
|
|
8
|
-
*
|
|
9
|
-
* @param params - The rule creation parameters (plugin name, rule name, language, test preference).
|
|
10
|
-
* @returns The scaffold result containing generated files and dependencies.
|
|
11
|
-
* @throws {CreateRuleHelperError} If the target plugin directory already exists.
|
|
12
|
-
*/
|
|
13
5
|
export async function createRuleToProject({ pluginName, ruleName, lang, needTest, }) {
|
|
14
6
|
const pluginDir = path.resolve(process.cwd(), pluginName);
|
|
15
7
|
if (await fsExists(pluginDir)) {
|
package/lib/fs-exists.d.ts
CHANGED
|
@@ -1,10 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Checks whether a file or directory exists at the given path.
|
|
3
|
-
*
|
|
4
|
-
* Uses `fs.stat` internally and treats `ENOENT` errors as a non-existent path.
|
|
5
|
-
* Any other filesystem errors are re-thrown.
|
|
6
|
-
*
|
|
7
|
-
* @param path - The absolute or relative filesystem path to check.
|
|
8
|
-
* @returns `true` if the path exists, `false` otherwise.
|
|
9
|
-
*/
|
|
10
1
|
export declare function fsExists(path: string): Promise<boolean>;
|
package/lib/fs-exists.js
CHANGED
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
import { stat } from 'node:fs/promises';
|
|
2
|
-
/**
|
|
3
|
-
* Checks whether a file or directory exists at the given path.
|
|
4
|
-
*
|
|
5
|
-
* Uses `fs.stat` internally and treats `ENOENT` errors as a non-existent path.
|
|
6
|
-
* Any other filesystem errors are re-thrown.
|
|
7
|
-
*
|
|
8
|
-
* @param path - The absolute or relative filesystem path to check.
|
|
9
|
-
* @returns `true` if the path exists, `false` otherwise.
|
|
10
|
-
*/
|
|
11
2
|
export async function fsExists(path) {
|
|
12
3
|
const res = await stat(path).catch(error => {
|
|
13
4
|
if (error?.code === 'ENOENT') {
|
package/lib/glob.d.ts
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Cross-platform glob wrapper that normalizes path separators before matching.
|
|
3
|
-
*
|
|
4
2
|
* Converts backslashes (Windows `path.sep`) to forward slashes so that
|
|
5
3
|
* glob patterns work consistently across operating systems.
|
|
6
|
-
*
|
|
7
|
-
* @param pattern - The glob pattern to match against (may contain OS-specific separators).
|
|
8
|
-
* @returns An array of file paths matching the pattern.
|
|
9
4
|
*/
|
|
10
5
|
export declare const glob: (pattern: string) => Promise<string[]>;
|
package/lib/glob.js
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { glob as origin } from 'glob';
|
|
3
3
|
/**
|
|
4
|
-
* Cross-platform glob wrapper that normalizes path separators before matching.
|
|
5
|
-
*
|
|
6
4
|
* Converts backslashes (Windows `path.sep`) to forward slashes so that
|
|
7
5
|
* glob patterns work consistently across operating systems.
|
|
8
|
-
*
|
|
9
|
-
* @param pattern - The glob pattern to match against (may contain OS-specific separators).
|
|
10
|
-
* @returns An array of file paths matching the pattern.
|
|
11
6
|
*/
|
|
12
7
|
export const glob = async (pattern) => {
|
|
13
8
|
const normalized = pattern.split(path.sep).join('/');
|
|
@@ -1,18 +1,4 @@
|
|
|
1
1
|
import type { CreateRuleCreatorParams, CreateRuleHelperResult } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Installs scaffold template files to the destination directory and optionally
|
|
4
|
-
* generates a `package.json` with appropriate scripts and dependency declarations.
|
|
5
|
-
*
|
|
6
|
-
* This is the low-level function used by all scaffold strategies (core, project, package).
|
|
7
|
-
* It copies template files from the built-in `scaffold/<type>` directory, applies
|
|
8
|
-
* placeholder replacements, and sets up the project structure.
|
|
9
|
-
*
|
|
10
|
-
* @param scaffoldType - The type of scaffold to install ("core", "project", or "package").
|
|
11
|
-
* @param dest - The absolute path to the destination directory.
|
|
12
|
-
* @param params - The creation parameters, extended with an optional `packageJson` flag
|
|
13
|
-
* indicating whether to generate a `package.json` file.
|
|
14
|
-
* @returns The scaffold result containing the list of generated files and dependency arrays.
|
|
15
|
-
*/
|
|
16
2
|
export declare function installScaffold(scaffoldType: 'core' | 'project' | 'package', dest: string, params: CreateRuleCreatorParams & {
|
|
17
3
|
readonly packageJson?: boolean;
|
|
18
4
|
}): Promise<CreateRuleHelperResult>;
|
package/lib/install-scaffold.js
CHANGED
|
@@ -2,20 +2,6 @@ import fs from 'node:fs/promises';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { fsExists } from './fs-exists.js';
|
|
4
4
|
import { transfer } from './transfer.js';
|
|
5
|
-
/**
|
|
6
|
-
* Installs scaffold template files to the destination directory and optionally
|
|
7
|
-
* generates a `package.json` with appropriate scripts and dependency declarations.
|
|
8
|
-
*
|
|
9
|
-
* This is the low-level function used by all scaffold strategies (core, project, package).
|
|
10
|
-
* It copies template files from the built-in `scaffold/<type>` directory, applies
|
|
11
|
-
* placeholder replacements, and sets up the project structure.
|
|
12
|
-
*
|
|
13
|
-
* @param scaffoldType - The type of scaffold to install ("core", "project", or "package").
|
|
14
|
-
* @param dest - The absolute path to the destination directory.
|
|
15
|
-
* @param params - The creation parameters, extended with an optional `packageJson` flag
|
|
16
|
-
* indicating whether to generate a `package.json` file.
|
|
17
|
-
* @returns The scaffold result containing the list of generated files and dependency arrays.
|
|
18
|
-
*/
|
|
19
5
|
export async function installScaffold(scaffoldType, dest, params) {
|
|
20
6
|
const exists = await fsExists(dest);
|
|
21
7
|
if (!exists) {
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* core monorepo. This is used to conditionally offer the "Contribute to core"
|
|
4
|
-
* option in the CLI wizard.
|
|
5
|
-
*
|
|
6
|
-
* @returns `true` if the cwd is within the markuplint monorepo, `false` otherwise.
|
|
2
|
+
* Used to conditionally offer the "Contribute to core" option in the CLI wizard.
|
|
7
3
|
*/
|
|
8
4
|
export declare function isMarkuplintRepo(): Promise<boolean>;
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { searchCoreRepository } from './search-core-repository.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
* core monorepo. This is used to conditionally offer the "Contribute to core"
|
|
5
|
-
* option in the CLI wizard.
|
|
6
|
-
*
|
|
7
|
-
* @returns `true` if the cwd is within the markuplint monorepo, `false` otherwise.
|
|
3
|
+
* Used to conditionally offer the "Contribute to core" option in the CLI wizard.
|
|
8
4
|
*/
|
|
9
5
|
export async function isMarkuplintRepo() {
|
|
10
6
|
const rootDir = await searchCoreRepository();
|
|
@@ -1,8 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reads the `package.json` file in the given directory and extracts the package name.
|
|
3
|
-
*
|
|
4
|
-
* @param dir - The directory containing the `package.json` file.
|
|
5
|
-
* @returns The `name` field from the package.json, or `null` if the file
|
|
6
|
-
* does not exist, cannot be parsed, or has no `name` field.
|
|
7
|
-
*/
|
|
8
1
|
export declare function readPackageJson(dir: string): Promise<string | null>;
|
package/lib/read-package-json.js
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
/**
|
|
4
|
-
* Reads the `package.json` file in the given directory and extracts the package name.
|
|
5
|
-
*
|
|
6
|
-
* @param dir - The directory containing the `package.json` file.
|
|
7
|
-
* @returns The `name` field from the package.json, or `null` if the file
|
|
8
|
-
* does not exist, cannot be parsed, or has no `name` field.
|
|
9
|
-
*/
|
|
10
3
|
export async function readPackageJson(dir) {
|
|
11
4
|
const filePath = path.resolve(dir, 'package.json');
|
|
12
5
|
try {
|
|
@@ -1,9 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Searches for the markuplint core monorepo root by traversing up from the
|
|
3
|
-
* current working directory. Identifies the root by checking for a
|
|
4
|
-
* `package.json` with the name `"markuplint-packages"`.
|
|
5
|
-
*
|
|
6
|
-
* @returns The absolute path to the monorepo root directory, or `null` if
|
|
7
|
-
* the current working directory is not within the markuplint repository.
|
|
8
|
-
*/
|
|
9
1
|
export declare function searchCoreRepository(): Promise<string | null>;
|
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { readPackageJson } from './read-package-json.js';
|
|
3
|
-
/**
|
|
4
|
-
* Searches for the markuplint core monorepo root by traversing up from the
|
|
5
|
-
* current working directory. Identifies the root by checking for a
|
|
6
|
-
* `package.json` with the name `"markuplint-packages"`.
|
|
7
|
-
*
|
|
8
|
-
* @returns The absolute path to the monorepo root directory, or `null` if
|
|
9
|
-
* the current working directory is not within the markuplint repository.
|
|
10
|
-
*/
|
|
11
3
|
export async function searchCoreRepository() {
|
|
12
4
|
const paths = path.resolve(process.cwd()).split(path.sep);
|
|
13
5
|
while (true) {
|
package/lib/transfer.d.ts
CHANGED
|
@@ -1,27 +1,13 @@
|
|
|
1
1
|
import type { File } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Options controlling how scaffold files are transferred to their destination.
|
|
4
|
-
*/
|
|
5
2
|
type TransferOptions = {
|
|
6
|
-
/** Whether to transpile TypeScript files to JavaScript. */
|
|
7
3
|
readonly transpile?: boolean;
|
|
8
|
-
/** Whether to include test files in the transfer. */
|
|
9
4
|
readonly test?: boolean;
|
|
10
|
-
/** A mapping of placeholder names to replacement values for template substitution. */
|
|
11
5
|
readonly replacer?: Readonly<Record<string, string | void>>;
|
|
12
6
|
};
|
|
13
7
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* optional TypeScript-to-JavaScript transpilation, and Prettier formatting, then
|
|
18
|
-
* writes the results to `destDir`.
|
|
19
|
-
*
|
|
20
|
-
* @param scaffoldType - The type of scaffold being transferred ("core", "project", or "package").
|
|
21
|
-
* @param baseDir - The source directory containing scaffold template files.
|
|
22
|
-
* @param destDir - The destination directory where processed files will be written.
|
|
23
|
-
* @param options - Optional settings for transpilation, test inclusion, and placeholder replacement.
|
|
24
|
-
* @returns An array of file metadata for each successfully transferred file.
|
|
8
|
+
* Template authoring constraint: because users may choose JavaScript output, every
|
|
9
|
+
* `.ts` template under `scaffold/` must remain a correct example after `tsc.transpile()`
|
|
10
|
+
* strips its type syntax.
|
|
25
11
|
*/
|
|
26
12
|
export declare function transfer(scaffoldType: 'core' | 'project' | 'package', baseDir: string, destDir: string, options?: TransferOptions): Promise<File[]>;
|
|
27
13
|
export {};
|
package/lib/transfer.js
CHANGED
|
@@ -7,17 +7,9 @@ import { fsExists } from './fs-exists.js';
|
|
|
7
7
|
import { glob } from './glob.js';
|
|
8
8
|
const { transpile, ScriptTarget } = tsc;
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* optional TypeScript-to-JavaScript transpilation, and Prettier formatting, then
|
|
14
|
-
* writes the results to `destDir`.
|
|
15
|
-
*
|
|
16
|
-
* @param scaffoldType - The type of scaffold being transferred ("core", "project", or "package").
|
|
17
|
-
* @param baseDir - The source directory containing scaffold template files.
|
|
18
|
-
* @param destDir - The destination directory where processed files will be written.
|
|
19
|
-
* @param options - Optional settings for transpilation, test inclusion, and placeholder replacement.
|
|
20
|
-
* @returns An array of file metadata for each successfully transferred file.
|
|
10
|
+
* Template authoring constraint: because users may choose JavaScript output, every
|
|
11
|
+
* `.ts` template under `scaffold/` must remain a correct example after `tsc.transpile()`
|
|
12
|
+
* strips its type syntax.
|
|
21
13
|
*/
|
|
22
14
|
export async function transfer(scaffoldType, baseDir, destDir, options) {
|
|
23
15
|
const files = await scan(baseDir, destDir);
|
|
@@ -51,7 +43,10 @@ async function transferFile(scaffoldType, file, options) {
|
|
|
51
43
|
contents = contents.replaceAll(new RegExp(`__${before}__`, 'g'), after);
|
|
52
44
|
}
|
|
53
45
|
}
|
|
54
|
-
// Remove prettier ignore comment
|
|
46
|
+
// Remove prettier ignore comment.
|
|
47
|
+
// The markers exist only so that formatters do not rewrite placeholder expressions
|
|
48
|
+
// (e.g. `__ruleName__c`) inside the scaffold templates; the output is fully
|
|
49
|
+
// reformatted by Prettier below, and generated files must not inherit the markers.
|
|
55
50
|
contents = contents.replace(/\n\s*\/\/ prettier-ignore/, '');
|
|
56
51
|
contents = contents.replace(/\n\s*<!-- prettier-ignore(?:-(?:start|end))? -->/, '');
|
|
57
52
|
const newFile = { ...file };
|
|
@@ -62,6 +57,7 @@ async function transferFile(scaffoldType, file, options) {
|
|
|
62
57
|
target: ScriptTarget.ESNext,
|
|
63
58
|
}, newFile.filePath);
|
|
64
59
|
// Insert new line before comments and the export keyword
|
|
60
|
+
// to restore readability, since transpiling drops the blank lines.
|
|
65
61
|
contents = contents.replaceAll(/(\n)(\s+\/\*\*|export)/g, '$1\n$2');
|
|
66
62
|
}
|
|
67
63
|
const candidateName = options?.replacer?.[newFile.name.replaceAll('_', '')];
|