@platformos/platformos-check-node 0.0.19 → 0.0.20
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 +42 -0
- package/configs/all.yml +6 -0
- package/configs/recommended.yml +6 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +68 -7
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -4,6 +4,48 @@ This is the Node.js wrapper of the runtime-agnostic [`@platformos/platformos-che
|
|
|
4
4
|
|
|
5
5
|
See the [@platformos/platformos-check-common README](../platformos-check-common) for more details.
|
|
6
6
|
|
|
7
|
+
## Entrypoints
|
|
8
|
+
|
|
9
|
+
| Function | Use |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `check(root, configPath?)` | Lint a whole project on disk; returns `Offense[]`. |
|
|
12
|
+
| `appCheckRun(root, configPath?, log?)` | Same, but also returns the resolved `App` and `Config`. |
|
|
13
|
+
| `checkAndAutofix(root, configPath?)` | Lint then apply safe autofixes to disk. |
|
|
14
|
+
| `lintBuffer(params)` | Lint a single in-memory buffer in the context of its on-disk project. |
|
|
15
|
+
|
|
16
|
+
### `lintBuffer` — lint one buffer with project overlay
|
|
17
|
+
|
|
18
|
+
`lintBuffer` is the typed seam an embedding tool (e.g. the MCP supervisor) lints
|
|
19
|
+
through — a **direct library call, not an LSP and not a subprocess**. It loads
|
|
20
|
+
the project from disk so cross-file checks (`MissingPartial`, `MissingPage`,
|
|
21
|
+
`OrphanedPartial`, …) resolve against real files, overlays the buffer under edit
|
|
22
|
+
in memory so the **unsaved** content is what gets linted and cross-referenced,
|
|
23
|
+
and returns the structured check-common `Offense[]` for that file with `fix` /
|
|
24
|
+
`suggest` and every typed field intact — no message-string round-trip.
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { lintBuffer } from '@platformos/platformos-check-node';
|
|
28
|
+
|
|
29
|
+
const offenses = await lintBuffer({
|
|
30
|
+
root: '/abs/path/to/project', // project root (absolute)
|
|
31
|
+
filePath: '/abs/path/to/project/app/views/pages/contact.liquid', // file under edit (absolute)
|
|
32
|
+
content: editorBufferContents, // unsaved buffer
|
|
33
|
+
// configPath?: explicit config; resolved from root when omitted
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
for (const offense of offenses) {
|
|
37
|
+
offense.check; // e.g. 'MissingPartial'
|
|
38
|
+
offense.severity; // Severity
|
|
39
|
+
offense.start.index; offense.end.index; // 0-based offsets
|
|
40
|
+
offense.fix; // optional Fixer (safe autofix)
|
|
41
|
+
offense.suggest; // optional Suggestion[] (manual fixes)
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
When `filePath` already exists in the project its on-disk source is replaced by
|
|
46
|
+
the buffer; when it is new (not yet saved) the buffer is added so it is still
|
|
47
|
+
linted. Only offenses for the buffer's file are returned.
|
|
48
|
+
|
|
7
49
|
## License
|
|
8
50
|
|
|
9
51
|
MIT.
|
package/configs/all.yml
CHANGED
|
@@ -42,6 +42,9 @@ MatchingTranslations:
|
|
|
42
42
|
MissingAsset:
|
|
43
43
|
enabled: true
|
|
44
44
|
severity: 0
|
|
45
|
+
MissingContentForLayout:
|
|
46
|
+
enabled: true
|
|
47
|
+
severity: 0
|
|
45
48
|
MissingPage:
|
|
46
49
|
enabled: true
|
|
47
50
|
severity: 1
|
|
@@ -64,6 +67,9 @@ ParserBlockingScript:
|
|
|
64
67
|
PartialCallArguments:
|
|
65
68
|
enabled: true
|
|
66
69
|
severity: 0
|
|
70
|
+
ReservedVariableName:
|
|
71
|
+
enabled: true
|
|
72
|
+
severity: 0
|
|
67
73
|
TranslationKeyExists:
|
|
68
74
|
enabled: true
|
|
69
75
|
severity: 0
|
package/configs/recommended.yml
CHANGED
|
@@ -42,6 +42,9 @@ MatchingTranslations:
|
|
|
42
42
|
MissingAsset:
|
|
43
43
|
enabled: true
|
|
44
44
|
severity: 0
|
|
45
|
+
MissingContentForLayout:
|
|
46
|
+
enabled: true
|
|
47
|
+
severity: 0
|
|
45
48
|
MissingPage:
|
|
46
49
|
enabled: true
|
|
47
50
|
severity: 1
|
|
@@ -64,6 +67,9 @@ ParserBlockingScript:
|
|
|
64
67
|
PartialCallArguments:
|
|
65
68
|
enabled: true
|
|
66
69
|
severity: 0
|
|
70
|
+
ReservedVariableName:
|
|
71
|
+
enabled: true
|
|
72
|
+
severity: 0
|
|
67
73
|
TranslationKeyExists:
|
|
68
74
|
enabled: true
|
|
69
75
|
severity: 0
|
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,33 @@ export declare function toSourceCode(absolutePath: string): Promise<LiquidSource
|
|
|
16
16
|
export declare function check(root: string, configPath?: string): Promise<Offense[]>;
|
|
17
17
|
export declare function checkAndAutofix(root: string, configPath?: string): Promise<void>;
|
|
18
18
|
export declare function appCheckRun(root: string, configPath?: string, log?: (message: string) => void): Promise<AppCheckRun>;
|
|
19
|
+
export interface LintBufferParams {
|
|
20
|
+
/** Absolute path to the project root. */
|
|
21
|
+
root: string;
|
|
22
|
+
/** Absolute path to the file under edit. */
|
|
23
|
+
filePath: string;
|
|
24
|
+
/** In-memory contents of the file under edit (may differ from, or not yet exist on, disk). */
|
|
25
|
+
content: string;
|
|
26
|
+
/** Explicit config path; resolved from `root` when omitted. */
|
|
27
|
+
configPath?: string;
|
|
28
|
+
log?: (message: string) => void;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Lint a single in-memory buffer in the context of its on-disk project.
|
|
32
|
+
*
|
|
33
|
+
* This is the typed seam the MCP supervisor lints through — NOT an LSP, NOT a
|
|
34
|
+
* subprocess. The on-disk project is loaded so cross-file checks
|
|
35
|
+
* (`MissingPartial`, `MissingPage`, `OrphanedPartial`, …) resolve against real
|
|
36
|
+
* files, and the buffer under edit is overlaid in memory so the UNSAVED content
|
|
37
|
+
* is what gets linted and cross-referenced. Returns the structured
|
|
38
|
+
* check-common `Offense[]` for the buffer's file, with `fix` / `suggest` and all
|
|
39
|
+
* typed fields preserved end to end (no message-string round-trip).
|
|
40
|
+
*
|
|
41
|
+
* `filePath` must be absolute. When it already exists in the project its
|
|
42
|
+
* on-disk `SourceCode` is replaced by the buffer; when it is new (not yet
|
|
43
|
+
* saved) the buffer is added so it is still linted.
|
|
44
|
+
*/
|
|
45
|
+
export declare function lintBuffer(params: LintBufferParams): Promise<Offense[]>;
|
|
19
46
|
export declare function getAppAndConfig(root: string, configPath?: string): Promise<{
|
|
20
47
|
app: App;
|
|
21
48
|
config: Config;
|
package/dist/index.js
CHANGED
|
@@ -23,6 +23,7 @@ exports.toSourceCode = toSourceCode;
|
|
|
23
23
|
exports.check = check;
|
|
24
24
|
exports.checkAndAutofix = checkAndAutofix;
|
|
25
25
|
exports.appCheckRun = appCheckRun;
|
|
26
|
+
exports.lintBuffer = lintBuffer;
|
|
26
27
|
exports.getAppAndConfig = getAppAndConfig;
|
|
27
28
|
exports.getApp = getApp;
|
|
28
29
|
exports.getAppFilesPathPattern = getAppFilesPathPattern;
|
|
@@ -70,6 +71,24 @@ async function checkAndAutofix(root, configPath) {
|
|
|
70
71
|
}
|
|
71
72
|
async function appCheckRun(root, configPath, log = () => { }) {
|
|
72
73
|
const { app, config } = await getAppAndConfig(root, configPath);
|
|
74
|
+
const offenses = await lintApp(root, app, config, log);
|
|
75
|
+
return {
|
|
76
|
+
app,
|
|
77
|
+
config,
|
|
78
|
+
offenses,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Run the configured checks over an in-memory `App` and return the structured
|
|
83
|
+
* `Offense[]` (with `fix` / `suggest` and all typed fields intact).
|
|
84
|
+
*
|
|
85
|
+
* Shared by {@link appCheckRun} (whole project on disk) and
|
|
86
|
+
* {@link lintBuffer} (project on disk + one buffer overlaid). Building the
|
|
87
|
+
* `getDocDefinition` map from the passed `app` is what lets the overlaid buffer
|
|
88
|
+
* be cross-referenced with its UNSAVED `{% doc %}` params rather than the
|
|
89
|
+
* stale on-disk version.
|
|
90
|
+
*/
|
|
91
|
+
async function lintApp(root, app, config, log = () => { }) {
|
|
73
92
|
const platformOSLiquidDocsManager = new platformos_check_docs_updater_1.PlatformOSLiquidDocsManager(log);
|
|
74
93
|
const validator = await platformos_check_common_1.JSONValidator.create(platformOSLiquidDocsManager, config);
|
|
75
94
|
const docDefinitions = new Map(app.map((file) => [
|
|
@@ -85,17 +104,52 @@ async function appCheckRun(root, configPath, log = () => { }) {
|
|
|
85
104
|
return (0, platformos_check_common_1.extractDocDefinition)(file.uri, ast);
|
|
86
105
|
}),
|
|
87
106
|
]));
|
|
88
|
-
|
|
107
|
+
return (0, platformos_check_common_1.check)(app, config, {
|
|
89
108
|
fs: NodeFileSystem_1.NodeFileSystem,
|
|
90
109
|
platformosDocset: platformOSLiquidDocsManager,
|
|
91
110
|
jsonValidationSet: platformOSLiquidDocsManager,
|
|
92
111
|
getDocDefinition: async (relativePath) => docDefinitions.get(relativePath)?.(),
|
|
93
112
|
});
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Lint a single in-memory buffer in the context of its on-disk project.
|
|
116
|
+
*
|
|
117
|
+
* This is the typed seam the MCP supervisor lints through — NOT an LSP, NOT a
|
|
118
|
+
* subprocess. The on-disk project is loaded so cross-file checks
|
|
119
|
+
* (`MissingPartial`, `MissingPage`, `OrphanedPartial`, …) resolve against real
|
|
120
|
+
* files, and the buffer under edit is overlaid in memory so the UNSAVED content
|
|
121
|
+
* is what gets linted and cross-referenced. Returns the structured
|
|
122
|
+
* check-common `Offense[]` for the buffer's file, with `fix` / `suggest` and all
|
|
123
|
+
* typed fields preserved end to end (no message-string round-trip).
|
|
124
|
+
*
|
|
125
|
+
* `filePath` must be absolute. When it already exists in the project its
|
|
126
|
+
* on-disk `SourceCode` is replaced by the buffer; when it is new (not yet
|
|
127
|
+
* saved) the buffer is added so it is still linted.
|
|
128
|
+
*/
|
|
129
|
+
async function lintBuffer(params) {
|
|
130
|
+
const { root, filePath, content, configPath, log = () => { } } = params;
|
|
131
|
+
const { app, config } = await getAppAndConfig(root, configPath);
|
|
132
|
+
const uri = platformos_check_common_1.path.normalize(vscode_uri_1.URI.file(filePath));
|
|
133
|
+
const overlaidApp = overlayBuffer(app, uri, content);
|
|
134
|
+
const offenses = await lintApp(root, overlaidApp, config, log);
|
|
135
|
+
return offenses.filter((offense) => offense.uri === uri);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Return a copy of `app` with the `SourceCode` for `uri` replaced by one built
|
|
139
|
+
* from `content`, appending it when the file is not already present.
|
|
140
|
+
*/
|
|
141
|
+
function overlayBuffer(app, uri, content) {
|
|
142
|
+
const overlay = (0, platformos_check_common_1.toSourceCode)(uri, content);
|
|
143
|
+
let replaced = false;
|
|
144
|
+
const next = app.map((file) => {
|
|
145
|
+
if (file.uri !== uri)
|
|
146
|
+
return file;
|
|
147
|
+
replaced = true;
|
|
148
|
+
return overlay;
|
|
149
|
+
});
|
|
150
|
+
if (!replaced)
|
|
151
|
+
next.push(overlay);
|
|
152
|
+
return next;
|
|
99
153
|
}
|
|
100
154
|
async function getAppAndConfig(root, configPath) {
|
|
101
155
|
const config = await (0, exports.loadConfig)(configPath, root);
|
|
@@ -127,13 +181,20 @@ async function getApp(config) {
|
|
|
127
181
|
// Schema files, generator templates (e.g. ERB .graphql), etc. are excluded.
|
|
128
182
|
if (filePath.endsWith('.graphql') && !(0, platformos_check_common_1.isKnownGraphQLFile)(filePath))
|
|
129
183
|
return false;
|
|
184
|
+
// Only lint .yml/.yaml files that belong to a recognized platformOS YAML
|
|
185
|
+
// directory (translations, custom model types, etc.). Config files like
|
|
186
|
+
// config.yml or .platformos-check.yml are excluded.
|
|
187
|
+
if ((filePath.endsWith('.yml') || filePath.endsWith('.yaml')) &&
|
|
188
|
+
!(0, platformos_check_common_1.isKnownYAMLFile)(filePath)) {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
130
191
|
return true;
|
|
131
192
|
}));
|
|
132
193
|
const sourceCodes = await Promise.all(paths.map(toSourceCode));
|
|
133
194
|
return sourceCodes.filter((x) => x !== undefined);
|
|
134
195
|
}
|
|
135
196
|
function getAppFilesPathPattern(rootUri) {
|
|
136
|
-
return (0, normalize_path_1.default)(node_path_1.default.join((0, node_url_1.fileURLToPath)(rootUri), '**/*.{liquid,
|
|
197
|
+
return (0, normalize_path_1.default)(node_path_1.default.join((0, node_url_1.fileURLToPath)(rootUri), '**/*.{liquid,graphql,yml,yaml}'));
|
|
137
198
|
}
|
|
138
199
|
/** @deprecated Use appCheckRun instead */
|
|
139
200
|
exports.runCheck = appCheckRun;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformos/platformos-check-node",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.20",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"author": "platformOS",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"type-check": "tsc --noEmit"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@platformos/platformos-check-common": "0.0.
|
|
37
|
-
"@platformos/platformos-check-docs-updater": "0.0.
|
|
36
|
+
"@platformos/platformos-check-common": "0.0.20",
|
|
37
|
+
"@platformos/platformos-check-docs-updater": "0.0.20",
|
|
38
38
|
"glob": "^13.0.0",
|
|
39
39
|
"normalize-path": "^3.0.0",
|
|
40
40
|
"vscode-uri": "^3.1.0",
|