@platformos/platformos-check-node 0.0.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/README.md +9 -0
- package/configs/all.yml +214 -0
- package/configs/nothing.yml +3 -0
- package/configs/recommended.yml +192 -0
- package/dist/NodeFileSystem.d.ts +2 -0
- package/dist/NodeFileSystem.js +37 -0
- package/dist/autofix.d.ts +6 -0
- package/dist/autofix.js +18 -0
- package/dist/backfill-docs/argument-collector.d.ts +6 -0
- package/dist/backfill-docs/argument-collector.js +167 -0
- package/dist/backfill-docs/doc-generator.d.ts +18 -0
- package/dist/backfill-docs/doc-generator.js +31 -0
- package/dist/backfill-docs/doc-updater.d.ts +13 -0
- package/dist/backfill-docs/doc-updater.js +154 -0
- package/dist/backfill-docs/index.d.ts +14 -0
- package/dist/backfill-docs/index.js +233 -0
- package/dist/backfill-docs/types.d.ts +32 -0
- package/dist/backfill-docs/types.js +3 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +47 -0
- package/dist/commands/generate-docs.d.ts +24 -0
- package/dist/commands/generate-docs.js +136 -0
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.js +7 -0
- package/dist/config/find-config-path.d.ts +1 -0
- package/dist/config/find-config-path.js +22 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.js +8 -0
- package/dist/config/installation-location.d.ts +1 -0
- package/dist/config/installation-location.js +20 -0
- package/dist/config/load-config-description.d.ts +10 -0
- package/dist/config/load-config-description.js +97 -0
- package/dist/config/load-config.d.ts +18 -0
- package/dist/config/load-config.js +30 -0
- package/dist/config/load-third-party-checks.d.ts +16 -0
- package/dist/config/load-third-party-checks.js +69 -0
- package/dist/config/resolve/index.d.ts +1 -0
- package/dist/config/resolve/index.js +6 -0
- package/dist/config/resolve/merge-fragments.d.ts +11 -0
- package/dist/config/resolve/merge-fragments.js +52 -0
- package/dist/config/resolve/read-yaml.d.ts +11 -0
- package/dist/config/resolve/read-yaml.js +205 -0
- package/dist/config/resolve/resolve-config.d.ts +8 -0
- package/dist/config/resolve/resolve-config.js +37 -0
- package/dist/config/types.d.ts +35 -0
- package/dist/config/types.js +19 -0
- package/dist/config/validation.d.ts +2 -0
- package/dist/config/validation.js +85 -0
- package/dist/file-utils.d.ts +1 -0
- package/dist/file-utils.js +17 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +160 -0
- package/dist/temp.d.ts +2 -0
- package/dist/temp.js +3 -0
- package/dist/test/test-helpers.d.ts +14 -0
- package/dist/test/test-helpers.js +119 -0
- package/package.json +45 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateParamLine = generateParamLine;
|
|
4
|
+
exports.generateDocTag = generateDocTag;
|
|
5
|
+
/**
|
|
6
|
+
* Generate a single @param line for a doc tag.
|
|
7
|
+
*
|
|
8
|
+
* @param name - The parameter name
|
|
9
|
+
* @param type - The inferred type
|
|
10
|
+
* @param isOptional - Whether to mark as optional with brackets
|
|
11
|
+
* @returns A formatted @param line like "@param {string} [name]" or "@param {string} name"
|
|
12
|
+
*/
|
|
13
|
+
function generateParamLine(name, type, isOptional = true) {
|
|
14
|
+
const paramName = isOptional ? `[${name}]` : name;
|
|
15
|
+
return `@param {${type}} ${paramName}`;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Generate a complete doc tag with param lines.
|
|
19
|
+
*
|
|
20
|
+
* @param params - Array of param line strings (without leading whitespace)
|
|
21
|
+
* @param indentation - The indentation to use for each line (default: 2 spaces)
|
|
22
|
+
* @returns A complete doc tag string
|
|
23
|
+
*/
|
|
24
|
+
function generateDocTag(params, indentation = ' ') {
|
|
25
|
+
if (params.length === 0) {
|
|
26
|
+
return `{% doc %}\n{% enddoc %}\n`;
|
|
27
|
+
}
|
|
28
|
+
const paramLines = params.map((p) => `${indentation}${p}`).join('\n');
|
|
29
|
+
return `{% doc %}\n${paramLines}\n{% enddoc %}\n`;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=doc-generator.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ExistingParam } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Update or insert a doc tag in a file's source code.
|
|
4
|
+
*
|
|
5
|
+
* @param source - The file source content
|
|
6
|
+
* @param paramsToAdd - Array of param line strings to add
|
|
7
|
+
* @returns The updated source content, or null if no changes needed
|
|
8
|
+
*/
|
|
9
|
+
export declare function updateDocInSource(source: string, paramsToAdd: string[]): Promise<string | null>;
|
|
10
|
+
/**
|
|
11
|
+
* Get the list of existing parameter names from a file.
|
|
12
|
+
*/
|
|
13
|
+
export declare function getExistingParams(source: string): Promise<ExistingParam[]>;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.updateDocInSource = updateDocInSource;
|
|
4
|
+
exports.getExistingParams = getExistingParams;
|
|
5
|
+
const liquid_html_parser_1 = require("@platformos/liquid-html-parser");
|
|
6
|
+
const platformos_check_common_1 = require("@platformos/platformos-check-common");
|
|
7
|
+
const liquid_html_parser_2 = require("@platformos/liquid-html-parser");
|
|
8
|
+
const doc_generator_1 = require("./doc-generator");
|
|
9
|
+
/**
|
|
10
|
+
* Parse a file to extract information about existing doc tags.
|
|
11
|
+
*/
|
|
12
|
+
async function parseDocTag(source) {
|
|
13
|
+
const result = {
|
|
14
|
+
exists: false,
|
|
15
|
+
startIndex: 0,
|
|
16
|
+
endIndex: 0,
|
|
17
|
+
existingParams: [],
|
|
18
|
+
lastParamEndIndex: 0,
|
|
19
|
+
docContent: '',
|
|
20
|
+
};
|
|
21
|
+
try {
|
|
22
|
+
const ast = (0, liquid_html_parser_1.toLiquidHtmlAST)(source);
|
|
23
|
+
if (!(0, liquid_html_parser_2.isLiquidHtmlNode)(ast)) {
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
await (0, platformos_check_common_1.visit)(ast, {
|
|
27
|
+
async LiquidRawTag(node) {
|
|
28
|
+
if (node.name !== 'doc')
|
|
29
|
+
return;
|
|
30
|
+
result.exists = true;
|
|
31
|
+
result.startIndex = node.position.start;
|
|
32
|
+
result.endIndex = node.position.end;
|
|
33
|
+
result.docContent = node.body.value;
|
|
34
|
+
},
|
|
35
|
+
async LiquidDocParamNode(node) {
|
|
36
|
+
result.existingParams.push({
|
|
37
|
+
name: node.paramName.value,
|
|
38
|
+
type: node.paramType?.value ?? null,
|
|
39
|
+
description: node.paramDescription?.value ?? null,
|
|
40
|
+
required: node.required,
|
|
41
|
+
});
|
|
42
|
+
// Track the end position of the last @param line
|
|
43
|
+
result.lastParamEndIndex = node.position.end;
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// Parse error - treat as no doc tag
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Find the correct insertion point for new @param lines within an existing doc tag.
|
|
54
|
+
* Inserts after the last @param line, or at the beginning if no params exist.
|
|
55
|
+
*/
|
|
56
|
+
function findInsertionPoint(docContent, existingParams) {
|
|
57
|
+
if (existingParams.length === 0) {
|
|
58
|
+
// No existing params, insert at the beginning of the doc content
|
|
59
|
+
// Find the first non-whitespace position after {% doc %}
|
|
60
|
+
const match = docContent.match(/^\s*/);
|
|
61
|
+
return match ? match[0].length : 0;
|
|
62
|
+
}
|
|
63
|
+
// Find the position after the last @param line
|
|
64
|
+
const lines = docContent.split('\n');
|
|
65
|
+
let lastParamLineIndex = -1;
|
|
66
|
+
for (let i = 0; i < lines.length; i++) {
|
|
67
|
+
if (lines[i].trim().startsWith('@param')) {
|
|
68
|
+
lastParamLineIndex = i;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (lastParamLineIndex === -1) {
|
|
72
|
+
return 0;
|
|
73
|
+
}
|
|
74
|
+
// Calculate the character offset to the end of the last @param line
|
|
75
|
+
let offset = 0;
|
|
76
|
+
for (let i = 0; i <= lastParamLineIndex; i++) {
|
|
77
|
+
offset += lines[i].length + 1; // +1 for newline
|
|
78
|
+
}
|
|
79
|
+
return offset - 1; // Position at the end of the last @param line
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Detect the indentation used in an existing doc tag.
|
|
83
|
+
*/
|
|
84
|
+
function detectIndentation(docContent) {
|
|
85
|
+
const lines = docContent.split('\n');
|
|
86
|
+
for (const line of lines) {
|
|
87
|
+
const match = line.match(/^(\s*)@param/);
|
|
88
|
+
if (match) {
|
|
89
|
+
return match[1];
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return ' '; // Default to 2 spaces
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Update or insert a doc tag in a file's source code.
|
|
96
|
+
*
|
|
97
|
+
* @param source - The file source content
|
|
98
|
+
* @param paramsToAdd - Array of param line strings to add
|
|
99
|
+
* @returns The updated source content, or null if no changes needed
|
|
100
|
+
*/
|
|
101
|
+
async function updateDocInSource(source, paramsToAdd) {
|
|
102
|
+
if (paramsToAdd.length === 0) {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
const docInfo = await parseDocTag(source);
|
|
106
|
+
if (!docInfo.exists) {
|
|
107
|
+
// No doc tag exists - create one at the start of the file
|
|
108
|
+
const newDocTag = (0, doc_generator_1.generateDocTag)(paramsToAdd);
|
|
109
|
+
return newDocTag + source;
|
|
110
|
+
}
|
|
111
|
+
// Doc tag exists - insert new params
|
|
112
|
+
const existingParamNames = new Set(docInfo.existingParams.map((p) => p.name));
|
|
113
|
+
// Filter out params that already exist
|
|
114
|
+
const newParams = paramsToAdd.filter((paramLine) => {
|
|
115
|
+
const match = paramLine.match(/@param\s+\{[^}]+\}\s+\[?(\w+)\]?/);
|
|
116
|
+
if (match) {
|
|
117
|
+
return !existingParamNames.has(match[1]);
|
|
118
|
+
}
|
|
119
|
+
return true;
|
|
120
|
+
});
|
|
121
|
+
if (newParams.length === 0) {
|
|
122
|
+
return null; // No new params to add
|
|
123
|
+
}
|
|
124
|
+
const indentation = detectIndentation(docInfo.docContent);
|
|
125
|
+
const insertionPoint = findInsertionPoint(docInfo.docContent, docInfo.existingParams);
|
|
126
|
+
// Build the new doc content
|
|
127
|
+
const newParamLines = newParams.map((p) => `${indentation}${p}`).join('\n');
|
|
128
|
+
// Insert the new params into the doc content
|
|
129
|
+
let newDocContent;
|
|
130
|
+
if (docInfo.existingParams.length === 0) {
|
|
131
|
+
// No existing params - add at the beginning with proper formatting
|
|
132
|
+
newDocContent = '\n' + newParamLines + docInfo.docContent;
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
// Has existing params - insert after the last one
|
|
136
|
+
const before = docInfo.docContent.slice(0, insertionPoint);
|
|
137
|
+
const after = docInfo.docContent.slice(insertionPoint);
|
|
138
|
+
newDocContent = before + '\n' + newParamLines + after;
|
|
139
|
+
}
|
|
140
|
+
// Reconstruct the doc tag
|
|
141
|
+
const newDocTag = `{% doc %}${newDocContent}{% enddoc %}`;
|
|
142
|
+
// Replace the old doc tag with the new one
|
|
143
|
+
return (source.slice(0, docInfo.startIndex) +
|
|
144
|
+
newDocTag +
|
|
145
|
+
source.slice(docInfo.endIndex));
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Get the list of existing parameter names from a file.
|
|
149
|
+
*/
|
|
150
|
+
async function getExistingParams(source) {
|
|
151
|
+
const docInfo = await parseDocTag(source);
|
|
152
|
+
return docInfo.existingParams;
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=doc-updater.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BackfillOptions, BackfillResult } from './types';
|
|
2
|
+
export { BackfillOptions, BackfillResult } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Run the doc tag backfill process.
|
|
5
|
+
*
|
|
6
|
+
* This scans the project for function, render, and include tag usages,
|
|
7
|
+
* collects the arguments passed to each partial, and updates/creates
|
|
8
|
+
* doc tags in the corresponding partial files.
|
|
9
|
+
*/
|
|
10
|
+
export declare function backfillDocs(options: BackfillOptions, log?: (message: string) => void): Promise<BackfillResult>;
|
|
11
|
+
/**
|
|
12
|
+
* CLI entry point for the backfill-docs command.
|
|
13
|
+
*/
|
|
14
|
+
export declare function runBackfillDocsCLI(args: string[]): Promise<void>;
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.backfillDocs = backfillDocs;
|
|
7
|
+
exports.runBackfillDocsCLI = runBackfillDocsCLI;
|
|
8
|
+
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const vscode_uri_1 = require("vscode-uri");
|
|
11
|
+
const platformos_common_1 = require("@platformos/platformos-common");
|
|
12
|
+
const platformos_check_common_1 = require("@platformos/platformos-check-common");
|
|
13
|
+
const liquid_html_parser_1 = require("@platformos/liquid-html-parser");
|
|
14
|
+
const index_1 = require("../index");
|
|
15
|
+
const NodeFileSystem_1 = require("../NodeFileSystem");
|
|
16
|
+
const argument_collector_1 = require("./argument-collector");
|
|
17
|
+
const doc_generator_1 = require("./doc-generator");
|
|
18
|
+
const doc_updater_1 = require("./doc-updater");
|
|
19
|
+
/**
|
|
20
|
+
* Extract the set of variable names used in a Liquid source file.
|
|
21
|
+
* Only looks at top-level variable lookups (the root name, not nested properties).
|
|
22
|
+
*/
|
|
23
|
+
async function getUsedVariables(source) {
|
|
24
|
+
const usedVars = new Set();
|
|
25
|
+
try {
|
|
26
|
+
const ast = (0, liquid_html_parser_1.toLiquidHtmlAST)(source);
|
|
27
|
+
if (!(0, liquid_html_parser_1.isLiquidHtmlNode)(ast)) {
|
|
28
|
+
return usedVars;
|
|
29
|
+
}
|
|
30
|
+
await (0, platformos_check_common_1.visit)(ast, {
|
|
31
|
+
async VariableLookup(node) {
|
|
32
|
+
if (node.name) {
|
|
33
|
+
usedVars.add(node.name);
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Parse error - return empty set
|
|
40
|
+
}
|
|
41
|
+
return usedVars;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Run the doc tag backfill process.
|
|
45
|
+
*
|
|
46
|
+
* This scans the project for function, render, and include tag usages,
|
|
47
|
+
* collects the arguments passed to each partial, and updates/creates
|
|
48
|
+
* doc tags in the corresponding partial files.
|
|
49
|
+
*/
|
|
50
|
+
async function backfillDocs(options, log = console.log) {
|
|
51
|
+
const { rootPath, dryRun = false, markRequired = false, verbose = false } = options;
|
|
52
|
+
const result = {
|
|
53
|
+
modified: [],
|
|
54
|
+
skipped: [],
|
|
55
|
+
errors: [],
|
|
56
|
+
};
|
|
57
|
+
log('Scanning for partial usages (function, render, include)...');
|
|
58
|
+
// Load theme configuration
|
|
59
|
+
const config = await (0, index_1.loadConfig)(undefined, rootPath);
|
|
60
|
+
const theme = await (0, index_1.getTheme)(config);
|
|
61
|
+
// Collect all partial usages from the theme
|
|
62
|
+
const usageMap = await (0, argument_collector_1.collectPartialUsages)(theme, verbose, log);
|
|
63
|
+
const totalCalls = Array.from(usageMap.values()).reduce((sum, usage) => sum + Array.from(usage.arguments.values()).reduce((s, a) => s + a.usageCount, 0), 0);
|
|
64
|
+
log(`Found ${totalCalls} partial calls referencing ${usageMap.size} partials\n`);
|
|
65
|
+
if (usageMap.size === 0) {
|
|
66
|
+
log('No partial usages found.');
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
log('Processing:');
|
|
70
|
+
// Create a DocumentsLocator for resolving partial paths
|
|
71
|
+
const documentsLocator = new platformos_common_1.DocumentsLocator(NodeFileSystem_1.NodeFileSystem);
|
|
72
|
+
const rootUri = vscode_uri_1.URI.file(rootPath);
|
|
73
|
+
// Process each partial
|
|
74
|
+
for (const usage of usageMap.values()) {
|
|
75
|
+
const { partialPath, tagType, arguments: args } = usage;
|
|
76
|
+
try {
|
|
77
|
+
// Resolve the partial file path
|
|
78
|
+
const resolvedUri = await documentsLocator.locate(rootUri, tagType, partialPath);
|
|
79
|
+
if (!resolvedUri) {
|
|
80
|
+
log(` [!] ${partialPath} - File not found`);
|
|
81
|
+
result.errors.push({
|
|
82
|
+
file: partialPath,
|
|
83
|
+
error: 'File not found',
|
|
84
|
+
});
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
// Convert URI to filesystem path
|
|
88
|
+
const filePath = platformos_check_common_1.path.fsPath(resolvedUri);
|
|
89
|
+
// Read the file content
|
|
90
|
+
let source;
|
|
91
|
+
try {
|
|
92
|
+
source = await promises_1.default.readFile(filePath, 'utf8');
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
log(` [!] ${partialPath} - Failed to read file`);
|
|
96
|
+
result.errors.push({
|
|
97
|
+
file: partialPath,
|
|
98
|
+
error: `Failed to read file: ${err}`,
|
|
99
|
+
});
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
// Get existing params to filter out duplicates
|
|
103
|
+
const existingParams = await (0, doc_updater_1.getExistingParams)(source);
|
|
104
|
+
const existingParamNames = new Set(existingParams.map((p) => p.name));
|
|
105
|
+
// Get variables actually used in the partial
|
|
106
|
+
const usedVariables = await getUsedVariables(source);
|
|
107
|
+
// Generate param lines for new arguments only (if they're actually used)
|
|
108
|
+
const newParamLines = [];
|
|
109
|
+
const addedParams = [];
|
|
110
|
+
for (const [argName, argInfo] of args) {
|
|
111
|
+
if (existingParamNames.has(argName)) {
|
|
112
|
+
continue; // Skip params that already exist
|
|
113
|
+
}
|
|
114
|
+
if (!usedVariables.has(argName)) {
|
|
115
|
+
if (verbose) {
|
|
116
|
+
log(` [skip] ${argName} - not used in partial`);
|
|
117
|
+
}
|
|
118
|
+
continue; // Skip params that aren't used in the partial
|
|
119
|
+
}
|
|
120
|
+
newParamLines.push((0, doc_generator_1.generateParamLine)(argName, argInfo.inferredType, !markRequired));
|
|
121
|
+
addedParams.push(argName);
|
|
122
|
+
}
|
|
123
|
+
if (newParamLines.length === 0) {
|
|
124
|
+
if (verbose) {
|
|
125
|
+
log(` [=] ${partialPath} - No changes needed`);
|
|
126
|
+
}
|
|
127
|
+
result.skipped.push(partialPath);
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
// Update the source with new params
|
|
131
|
+
const updatedSource = await (0, doc_updater_1.updateDocInSource)(source, newParamLines);
|
|
132
|
+
if (!updatedSource) {
|
|
133
|
+
if (verbose) {
|
|
134
|
+
log(` [=] ${partialPath} - No changes needed`);
|
|
135
|
+
}
|
|
136
|
+
result.skipped.push(partialPath);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
// Write the updated content (unless dry run)
|
|
140
|
+
if (!dryRun) {
|
|
141
|
+
await promises_1.default.writeFile(filePath, updatedSource, 'utf8');
|
|
142
|
+
}
|
|
143
|
+
const relativePath = node_path_1.default.relative(rootPath, filePath);
|
|
144
|
+
log(` [+] ${relativePath} - Added: ${addedParams.join(', ')}`);
|
|
145
|
+
result.modified.push(partialPath);
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
log(` [!] ${partialPath} - Error: ${err}`);
|
|
149
|
+
result.errors.push({
|
|
150
|
+
file: partialPath,
|
|
151
|
+
error: String(err),
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// Print summary
|
|
156
|
+
log('');
|
|
157
|
+
log(`Modified: ${result.modified.length} files | Skipped: ${result.skipped.length} | Errors: ${result.errors.length}`);
|
|
158
|
+
if (dryRun && result.modified.length > 0) {
|
|
159
|
+
log('\n(Dry run - no files were actually modified)');
|
|
160
|
+
}
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* CLI entry point for the backfill-docs command.
|
|
165
|
+
*/
|
|
166
|
+
async function runBackfillDocsCLI(args) {
|
|
167
|
+
const options = {
|
|
168
|
+
rootPath: process.cwd(),
|
|
169
|
+
dryRun: false,
|
|
170
|
+
markRequired: false,
|
|
171
|
+
verbose: false,
|
|
172
|
+
};
|
|
173
|
+
// Parse command line arguments
|
|
174
|
+
const positionalArgs = [];
|
|
175
|
+
for (let i = 0; i < args.length; i++) {
|
|
176
|
+
const arg = args[i];
|
|
177
|
+
if (arg === '--dry-run' || arg === '-n') {
|
|
178
|
+
options.dryRun = true;
|
|
179
|
+
}
|
|
180
|
+
else if (arg === '--required' || arg === '-r') {
|
|
181
|
+
options.markRequired = true;
|
|
182
|
+
}
|
|
183
|
+
else if (arg === '--verbose' || arg === '-v') {
|
|
184
|
+
options.verbose = true;
|
|
185
|
+
}
|
|
186
|
+
else if (arg === '--help' || arg === '-h') {
|
|
187
|
+
printHelp();
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
else if (!arg.startsWith('-')) {
|
|
191
|
+
positionalArgs.push(arg);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
console.error(`Unknown option: ${arg}`);
|
|
195
|
+
printHelp();
|
|
196
|
+
process.exit(1);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// First positional argument is the path
|
|
200
|
+
if (positionalArgs.length > 0) {
|
|
201
|
+
options.rootPath = node_path_1.default.resolve(positionalArgs[0]);
|
|
202
|
+
}
|
|
203
|
+
try {
|
|
204
|
+
await backfillDocs(options);
|
|
205
|
+
}
|
|
206
|
+
catch (err) {
|
|
207
|
+
console.error('Error:', err);
|
|
208
|
+
process.exit(1);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function printHelp() {
|
|
212
|
+
console.log(`
|
|
213
|
+
Usage: theme-check backfill-docs [path] [options]
|
|
214
|
+
|
|
215
|
+
Scans a platformOS project for partial usages (function, render, include tags)
|
|
216
|
+
and backfills or updates {% doc %} tags in the corresponding partial files.
|
|
217
|
+
|
|
218
|
+
Arguments:
|
|
219
|
+
path Path to the project root (default: current directory)
|
|
220
|
+
|
|
221
|
+
Options:
|
|
222
|
+
--dry-run, -n Preview changes without writing files
|
|
223
|
+
--required, -r Mark new params as required (default: optional)
|
|
224
|
+
--verbose, -v Show detailed progress
|
|
225
|
+
--help, -h Show this help message
|
|
226
|
+
|
|
227
|
+
Examples:
|
|
228
|
+
theme-check backfill-docs
|
|
229
|
+
theme-check backfill-docs ./my-project --dry-run
|
|
230
|
+
theme-check backfill-docs --verbose --required
|
|
231
|
+
`);
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { BasicParamTypes } from '@platformos/platformos-check-common';
|
|
2
|
+
export type TagType = 'function' | 'render' | 'include';
|
|
3
|
+
export interface ArgumentInfo {
|
|
4
|
+
name: string;
|
|
5
|
+
inferredType: BasicParamTypes;
|
|
6
|
+
usageCount: number;
|
|
7
|
+
}
|
|
8
|
+
export interface PartialUsage {
|
|
9
|
+
partialPath: string;
|
|
10
|
+
tagType: TagType;
|
|
11
|
+
arguments: Map<string, ArgumentInfo>;
|
|
12
|
+
}
|
|
13
|
+
export interface BackfillOptions {
|
|
14
|
+
rootPath: string;
|
|
15
|
+
dryRun?: boolean;
|
|
16
|
+
markRequired?: boolean;
|
|
17
|
+
verbose?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface BackfillResult {
|
|
20
|
+
modified: string[];
|
|
21
|
+
skipped: string[];
|
|
22
|
+
errors: Array<{
|
|
23
|
+
file: string;
|
|
24
|
+
error: string;
|
|
25
|
+
}>;
|
|
26
|
+
}
|
|
27
|
+
export interface ExistingParam {
|
|
28
|
+
name: string;
|
|
29
|
+
type: string | null;
|
|
30
|
+
description: string | null;
|
|
31
|
+
required: boolean;
|
|
32
|
+
}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const index_1 = require("./index");
|
|
7
|
+
const backfill_docs_1 = require("./backfill-docs");
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
async function runThemeCheck(args) {
|
|
10
|
+
const root = node_path_1.default.resolve(args[0] || '.');
|
|
11
|
+
const configPath = args[1] ? node_path_1.default.resolve(args[1]) : undefined;
|
|
12
|
+
const { theme, config, offenses } = await (0, index_1.themeCheckRun)(root, configPath, console.error.bind(console));
|
|
13
|
+
console.log(JSON.stringify(offenses, null, 2));
|
|
14
|
+
console.log(JSON.stringify(config, null, 2));
|
|
15
|
+
console.log(JSON.stringify(theme.map((x) => x.uri), null, 2));
|
|
16
|
+
}
|
|
17
|
+
function printUsage() {
|
|
18
|
+
console.log(`
|
|
19
|
+
Usage: theme-check [command] [options]
|
|
20
|
+
|
|
21
|
+
Commands:
|
|
22
|
+
<path> Run theme checks on the specified path (default)
|
|
23
|
+
backfill-docs Backfill doc tags in partial files based on usage
|
|
24
|
+
|
|
25
|
+
Run 'theme-check <command> --help' for more information on a command.
|
|
26
|
+
`);
|
|
27
|
+
}
|
|
28
|
+
async function main() {
|
|
29
|
+
const args = process.argv.slice(2);
|
|
30
|
+
if (args.length === 0) {
|
|
31
|
+
printUsage();
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
const command = args[0];
|
|
35
|
+
if (command === '--help' || command === '-h') {
|
|
36
|
+
printUsage();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (command === 'backfill-docs') {
|
|
40
|
+
await (0, backfill_docs_1.runBackfillDocsCLI)(args.slice(1));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
// Default: run theme check
|
|
44
|
+
await runThemeCheck(args);
|
|
45
|
+
}
|
|
46
|
+
main();
|
|
47
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface GenerateDocsOptions {
|
|
2
|
+
dryRun?: boolean;
|
|
3
|
+
output?: 'inline' | 'stdout' | 'json';
|
|
4
|
+
}
|
|
5
|
+
export interface GenerateDocsResult {
|
|
6
|
+
uri: string;
|
|
7
|
+
relativePath: string;
|
|
8
|
+
parameters: Array<{
|
|
9
|
+
name: string;
|
|
10
|
+
type: string | null;
|
|
11
|
+
isOptional: boolean;
|
|
12
|
+
}>;
|
|
13
|
+
docBlockText: string;
|
|
14
|
+
hasExistingDocBlock: boolean;
|
|
15
|
+
updated: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Generate doc blocks for all partials and blocks in a theme.
|
|
19
|
+
*/
|
|
20
|
+
export declare function generateDocsCommand(root: string, options?: GenerateDocsOptions): Promise<GenerateDocsResult[]>;
|
|
21
|
+
/**
|
|
22
|
+
* Generate doc block for a single file.
|
|
23
|
+
*/
|
|
24
|
+
export declare function generateDocForFile(absolutePath: string, options?: GenerateDocsOptions): Promise<GenerateDocsResult | null>;
|