@platformos/platformos-graph 0.0.19 → 0.1.0

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.
Files changed (141) hide show
  1. package/CHANGELOG.md +516 -0
  2. package/bin/platformos-graph +21 -81
  3. package/dist/cache-probes.spec.d.ts +1 -0
  4. package/dist/cache-probes.spec.js +62 -0
  5. package/dist/cache-probes.spec.js.map +1 -0
  6. package/dist/cli.d.ts +46 -0
  7. package/dist/cli.js +131 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/cli.spec.d.ts +1 -0
  10. package/dist/cli.spec.js +235 -0
  11. package/dist/cli.spec.js.map +1 -0
  12. package/dist/graph/app-index-resolution.spec.d.ts +1 -0
  13. package/dist/graph/app-index-resolution.spec.js +167 -0
  14. package/dist/graph/app-index-resolution.spec.js.map +1 -0
  15. package/dist/graph/asset-resolution.spec.d.ts +1 -0
  16. package/dist/graph/asset-resolution.spec.js +64 -0
  17. package/dist/graph/asset-resolution.spec.js.map +1 -0
  18. package/dist/graph/augment.js +3 -1
  19. package/dist/graph/augment.js.map +1 -1
  20. package/dist/graph/build.d.ts +15 -2
  21. package/dist/graph/build.js +54 -12
  22. package/dist/graph/build.js.map +1 -1
  23. package/dist/graph/build.spec.d.ts +1 -0
  24. package/dist/graph/build.spec.js +138 -0
  25. package/dist/graph/build.spec.js.map +1 -0
  26. package/dist/graph/edge-sources.d.ts +28 -0
  27. package/dist/graph/edge-sources.js +43 -0
  28. package/dist/graph/edge-sources.js.map +1 -0
  29. package/dist/graph/edge-sources.spec.d.ts +1 -0
  30. package/dist/graph/edge-sources.spec.js +125 -0
  31. package/dist/graph/edge-sources.spec.js.map +1 -0
  32. package/dist/graph/extract.spec.d.ts +1 -0
  33. package/dist/graph/extract.spec.js +163 -0
  34. package/dist/graph/extract.spec.js.map +1 -0
  35. package/dist/graph/module.d.ts +70 -2
  36. package/dist/graph/module.js +164 -29
  37. package/dist/graph/module.js.map +1 -1
  38. package/dist/graph/module.spec.d.ts +1 -0
  39. package/dist/graph/module.spec.js +74 -0
  40. package/dist/graph/module.spec.js.map +1 -0
  41. package/dist/graph/query.d.ts +72 -0
  42. package/dist/graph/query.js +140 -0
  43. package/dist/graph/query.js.map +1 -0
  44. package/dist/graph/query.spec.d.ts +1 -0
  45. package/dist/graph/query.spec.js +209 -0
  46. package/dist/graph/query.spec.js.map +1 -0
  47. package/dist/graph/serialize.spec.d.ts +1 -0
  48. package/dist/graph/serialize.spec.js +50 -0
  49. package/dist/graph/serialize.spec.js.map +1 -0
  50. package/dist/graph/structural.spec.d.ts +1 -0
  51. package/dist/graph/structural.spec.js +146 -0
  52. package/dist/graph/structural.spec.js.map +1 -0
  53. package/dist/graph/test-helpers.d.ts +2 -3
  54. package/dist/graph/test-helpers.js +5 -9
  55. package/dist/graph/test-helpers.js.map +1 -1
  56. package/dist/graph/traverse-edges.spec.d.ts +1 -0
  57. package/dist/graph/traverse-edges.spec.js +337 -0
  58. package/dist/graph/traverse-edges.spec.js.map +1 -0
  59. package/dist/graph/traverse.d.ts +63 -4
  60. package/dist/graph/traverse.js +364 -49
  61. package/dist/graph/traverse.js.map +1 -1
  62. package/dist/index.d.ts +5 -1
  63. package/dist/index.js +21 -4
  64. package/dist/index.js.map +1 -1
  65. package/dist/parsers.d.ts +35 -0
  66. package/dist/parsers.js +72 -0
  67. package/dist/parsers.js.map +1 -0
  68. package/dist/parsers.spec.d.ts +1 -0
  69. package/dist/parsers.spec.js +70 -0
  70. package/dist/parsers.spec.js.map +1 -0
  71. package/dist/toSourceCode.d.ts +14 -2
  72. package/dist/toSourceCode.js +23 -19
  73. package/dist/toSourceCode.js.map +1 -1
  74. package/dist/tsconfig.tsbuildinfo +1 -1
  75. package/dist/types.d.ts +114 -20
  76. package/dist/types.js.map +1 -1
  77. package/dist/utils/index.d.ts +1 -1
  78. package/fixtures/asset-edges/app/assets/logo.css +1 -0
  79. package/fixtures/asset-edges/app/assets/site/app.js +1 -0
  80. package/fixtures/asset-edges/app/views/pages/index.liquid +3 -0
  81. package/fixtures/background-edges/app/views/pages/broken.liquid +3 -0
  82. package/fixtures/background-edges/app/views/pages/index.liquid +3 -0
  83. package/fixtures/background-edges/app/views/partials/jobs/notify.liquid +3 -0
  84. package/fixtures/function-edges/app/lib/queries/list.liquid +3 -0
  85. package/fixtures/function-edges/app/views/pages/broken.liquid +3 -0
  86. package/fixtures/function-edges/app/views/pages/index.liquid +3 -0
  87. package/fixtures/graphql-edges/app/graphql/blog_posts/find.graphql +10 -0
  88. package/fixtures/graphql-edges/app/views/pages/broken.liquid +3 -0
  89. package/fixtures/graphql-edges/app/views/pages/index.liquid +3 -0
  90. package/fixtures/graphql-table/app/graphql/with_table.graphql +5 -0
  91. package/fixtures/graphql-table/app/graphql/without_table.graphql +3 -0
  92. package/fixtures/graphql-table/app/views/pages/index.liquid +4 -0
  93. package/fixtures/include-edges/app/views/pages/index.liquid +1 -0
  94. package/fixtures/include-edges/app/views/partials/shared/header.liquid +1 -0
  95. package/fixtures/layout-edges/app/views/layouts/theme.liquid +4 -0
  96. package/fixtures/layout-edges/app/views/pages/broken.liquid +5 -0
  97. package/fixtures/layout-edges/app/views/pages/index.liquid +5 -0
  98. package/fixtures/module-edges/app/views/pages/index.liquid +4 -0
  99. package/fixtures/module-edges/modules/my_module/public/lib/queries/get.liquid +3 -0
  100. package/fixtures/module-edges/modules/my_module/public/views/partials/card.liquid +1 -0
  101. package/fixtures/schema-nodes/app/schema/blog_post.yml +6 -0
  102. package/fixtures/schema-nodes/app/schema/no_name.yml +3 -0
  103. package/fixtures/schema-nodes/app/views/pages/index.liquid +1 -0
  104. package/fixtures/skeleton/app/assets/app.js +1 -0
  105. package/fixtures/skeleton/app/views/partials/child.liquid +2 -4
  106. package/fixtures/skeleton/app/views/partials/parent.liquid +2 -4
  107. package/fixtures/structural/app/views/pages/about.liquid +1 -0
  108. package/fixtures/structural/app/views/pages/blog/show.liquid +4 -0
  109. package/fixtures/structural/app/views/pages/index.liquid +6 -0
  110. package/fixtures/structural/app/views/pages/rich.liquid +8 -0
  111. package/fixtures/structural/app/views/partials/card.liquid +1 -0
  112. package/fixtures/structural/app/views/partials/documented.liquid +5 -0
  113. package/package.json +7 -5
  114. package/src/cli.spec.ts +271 -0
  115. package/src/cli.ts +167 -0
  116. package/src/graph/augment.ts +4 -2
  117. package/src/graph/build.spec.ts +888 -9
  118. package/src/graph/build.ts +68 -17
  119. package/src/graph/edge-sources.spec.ts +125 -0
  120. package/src/graph/edge-sources.ts +49 -0
  121. package/src/graph/module.spec.ts +168 -0
  122. package/src/graph/module.ts +167 -33
  123. package/src/graph/query.spec.ts +260 -0
  124. package/src/graph/query.ts +154 -0
  125. package/src/graph/serialize.spec.ts +4 -4
  126. package/src/graph/test-helpers.ts +5 -12
  127. package/src/graph/traverse.spec.ts +278 -0
  128. package/src/graph/traverse.ts +423 -54
  129. package/src/index.ts +16 -1
  130. package/src/parsers.spec.ts +85 -0
  131. package/src/parsers.ts +75 -0
  132. package/src/toSourceCode.ts +26 -26
  133. package/src/types.ts +120 -23
  134. package/src/utils/index.ts +1 -1
  135. package/bin/jsconfig.json +0 -18
  136. package/dist/getWebComponentMap.d.ts +0 -10
  137. package/dist/getWebComponentMap.js +0 -66
  138. package/dist/getWebComponentMap.js.map +0 -1
  139. package/fixtures/skeleton/assets/app.js +0 -7
  140. package/src/getWebComponentMap.ts +0 -81
  141. /package/fixtures/skeleton/{assets → app/assets}/app.css +0 -0
package/dist/index.js CHANGED
@@ -14,16 +14,33 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.toSourceCode = exports.parseJs = exports.findWebComponentReferences = exports.getWebComponentMap = exports.serializeAppGraph = exports.buildAppGraph = void 0;
17
+ exports.graphParsers = exports.appBackedGetSourceCode = exports.toSourceCode = exports.parseJs = exports.serializeAppGraph = exports.nearestModules = exports.missingTargets = exports.missingDependencies = exports.reachableFrom = exports.orphans = exports.isOrphan = exports.isEntryPoint = exports.exists = exports.dependentsOf = exports.dependenciesOf = exports.extractStructural = exports.extractFileReferences = exports.isEdgeSource = exports.enumerateEdgeSources = exports.buildAppGraph = void 0;
18
18
  var build_1 = require("./graph/build");
19
19
  Object.defineProperty(exports, "buildAppGraph", { enumerable: true, get: function () { return build_1.buildAppGraph; } });
20
+ var edge_sources_1 = require("./graph/edge-sources");
21
+ Object.defineProperty(exports, "enumerateEdgeSources", { enumerable: true, get: function () { return edge_sources_1.enumerateEdgeSources; } });
22
+ Object.defineProperty(exports, "isEdgeSource", { enumerable: true, get: function () { return edge_sources_1.isEdgeSource; } });
23
+ var traverse_1 = require("./graph/traverse");
24
+ Object.defineProperty(exports, "extractFileReferences", { enumerable: true, get: function () { return traverse_1.extractFileReferences; } });
25
+ Object.defineProperty(exports, "extractStructural", { enumerable: true, get: function () { return traverse_1.extractStructural; } });
26
+ var query_1 = require("./graph/query");
27
+ Object.defineProperty(exports, "dependenciesOf", { enumerable: true, get: function () { return query_1.dependenciesOf; } });
28
+ Object.defineProperty(exports, "dependentsOf", { enumerable: true, get: function () { return query_1.dependentsOf; } });
29
+ Object.defineProperty(exports, "exists", { enumerable: true, get: function () { return query_1.exists; } });
30
+ Object.defineProperty(exports, "isEntryPoint", { enumerable: true, get: function () { return query_1.isEntryPoint; } });
31
+ Object.defineProperty(exports, "isOrphan", { enumerable: true, get: function () { return query_1.isOrphan; } });
32
+ Object.defineProperty(exports, "orphans", { enumerable: true, get: function () { return query_1.orphans; } });
33
+ Object.defineProperty(exports, "reachableFrom", { enumerable: true, get: function () { return query_1.reachableFrom; } });
34
+ Object.defineProperty(exports, "missingDependencies", { enumerable: true, get: function () { return query_1.missingDependencies; } });
35
+ Object.defineProperty(exports, "missingTargets", { enumerable: true, get: function () { return query_1.missingTargets; } });
36
+ Object.defineProperty(exports, "nearestModules", { enumerable: true, get: function () { return query_1.nearestModules; } });
20
37
  var serialize_1 = require("./graph/serialize");
21
38
  Object.defineProperty(exports, "serializeAppGraph", { enumerable: true, get: function () { return serialize_1.serializeAppGraph; } });
22
- var getWebComponentMap_1 = require("./getWebComponentMap");
23
- Object.defineProperty(exports, "getWebComponentMap", { enumerable: true, get: function () { return getWebComponentMap_1.getWebComponentMap; } });
24
- Object.defineProperty(exports, "findWebComponentReferences", { enumerable: true, get: function () { return getWebComponentMap_1.findWebComponentReferences; } });
25
39
  var toSourceCode_1 = require("./toSourceCode");
26
40
  Object.defineProperty(exports, "parseJs", { enumerable: true, get: function () { return toSourceCode_1.parseJs; } });
27
41
  Object.defineProperty(exports, "toSourceCode", { enumerable: true, get: function () { return toSourceCode_1.toSourceCode; } });
42
+ var parsers_1 = require("./parsers");
43
+ Object.defineProperty(exports, "appBackedGetSourceCode", { enumerable: true, get: function () { return parsers_1.appBackedGetSourceCode; } });
44
+ Object.defineProperty(exports, "graphParsers", { enumerable: true, get: function () { return parsers_1.graphParsers; } });
28
45
  __exportStar(require("./types"), exports);
29
46
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,uCAA8C;AAArC,sGAAA,aAAa,OAAA;AACtB,+CAAsD;AAA7C,8GAAA,iBAAiB,OAAA;AAC1B,2DAAsF;AAA7E,wHAAA,kBAAkB,OAAA;AAAE,gIAAA,0BAA0B,OAAA;AACvD,+CAAuD;AAA9C,uGAAA,OAAO,OAAA;AAAE,4GAAA,YAAY,OAAA;AAC9B,0CAAwB"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,uCAA8C;AAArC,sGAAA,aAAa,OAAA;AACtB,qDAA0E;AAAjE,oHAAA,oBAAoB,OAAA;AAAE,4GAAA,YAAY,OAAA;AAC3C,6CAA4E;AAAnE,iHAAA,qBAAqB,OAAA;AAAE,6GAAA,iBAAiB,OAAA;AACjD,uCAWuB;AAVrB,uGAAA,cAAc,OAAA;AACd,qGAAA,YAAY,OAAA;AACZ,+FAAA,MAAM,OAAA;AACN,qGAAA,YAAY,OAAA;AACZ,iGAAA,QAAQ,OAAA;AACR,gGAAA,OAAO,OAAA;AACP,sGAAA,aAAa,OAAA;AACb,4GAAA,mBAAmB,OAAA;AACnB,uGAAA,cAAc,OAAA;AACd,uGAAA,cAAc,OAAA;AAGhB,+CAAsD;AAA7C,8GAAA,iBAAiB,OAAA;AAC1B,+CAAuD;AAA9C,uGAAA,OAAO,OAAA;AAAE,4GAAA,YAAY,OAAA;AAC9B,qCAAiE;AAAxD,iHAAA,sBAAsB,OAAA;AAAE,uGAAA,YAAY,OAAA;AAC7C,0CAAwB"}
@@ -0,0 +1,35 @@
1
+ import { App, Parsers, UriString } from '@platformos/platformos-common';
2
+ import { Program } from 'acorn';
3
+ import { FileSourceCode } from './types';
4
+ /** Parse a JavaScript asset, capturing a syntax error as a value rather than throwing. */
5
+ export declare function parseJs(source: string): Program | Error;
6
+ /**
7
+ * The file types the GRAPH holds and the linter does not: `.js` assets and images.
8
+ *
9
+ * They exist for {@link toSourceCode}'s contract — every URI it is handed comes back as a
10
+ * `FileSourceCode` — and so an `App` an asset URI is put into can answer `ast` at all. NOT
11
+ * because a graph build reads them: `traverseModule` returns immediately for an Asset node, and
12
+ * the only question the graph asks about an asset is whether it EXISTS.
13
+ *
14
+ * Registering them on an {@link App} — rather than building a second set of file objects — is
15
+ * what lets a graph build and a lint run over the same project hold the SAME `AppFile`
16
+ * instances, so each file is read and parsed at most once for both. The language server does
17
+ * that; check-node builds no graph, so merging into `nodeParsers` would do nothing.
18
+ *
19
+ * THE MCP SUPERVISOR DELIBERATELY DOES NOT SHARE, and this is not a pending to-do: it builds no
20
+ * graph, parsing per request only the handful of files that could reference the edited one.
21
+ * Routing those through check-node's shared `App` would win nothing — `lintBuffers` parses the
22
+ * content it was HANDED and drops the app's entry on the way out — and would risk something,
23
+ * because that `App` carries UNSAVED buffers while the blast radius runs CONCURRENTLY with the
24
+ * lint.
25
+ */
26
+ export declare const graphParsers: Parsers;
27
+ /**
28
+ * A `getSourceCode` for the graph backed by an {@link App}.
29
+ *
30
+ * Pass it as `IDependencies.getSourceCode` and the graph stops parsing anything the
31
+ * lint has already parsed, and vice versa — they read the same file objects. Files
32
+ * the app does not contain fall through to `fallback`, which is how a URI outside
33
+ * the project (or an unclassified file) still gets a source code.
34
+ */
35
+ export declare function appBackedGetSourceCode(app: App, fallback: (uri: UriString) => Promise<FileSourceCode>): (uri: UriString) => Promise<FileSourceCode>;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.graphParsers = void 0;
4
+ exports.parseJs = parseJs;
5
+ exports.appBackedGetSourceCode = appBackedGetSourceCode;
6
+ const platformos_check_common_1 = require("@platformos/platformos-check-common");
7
+ const acorn_1 = require("acorn");
8
+ const types_1 = require("./types");
9
+ /** Parse a JavaScript asset, capturing a syntax error as a value rather than throwing. */
10
+ function parseJs(source) {
11
+ try {
12
+ return (0, acorn_1.parse)(source, {
13
+ ecmaVersion: 'latest',
14
+ sourceType: 'module',
15
+ });
16
+ }
17
+ catch (error) {
18
+ return (0, platformos_check_common_1.asError)(error);
19
+ }
20
+ }
21
+ /**
22
+ * A binary asset has nothing to parse. It is still a graph node — something links
23
+ * to it — so it gets an `Error` value rather than being absent, exactly as an
24
+ * unparseable file would.
25
+ */
26
+ const parseOpaqueAsset = () => new Error('File parsing not implemented');
27
+ /**
28
+ * The file types the GRAPH holds and the linter does not: `.js` assets and images.
29
+ *
30
+ * They exist for {@link toSourceCode}'s contract — every URI it is handed comes back as a
31
+ * `FileSourceCode` — and so an `App` an asset URI is put into can answer `ast` at all. NOT
32
+ * because a graph build reads them: `traverseModule` returns immediately for an Asset node, and
33
+ * the only question the graph asks about an asset is whether it EXISTS.
34
+ *
35
+ * Registering them on an {@link App} — rather than building a second set of file objects — is
36
+ * what lets a graph build and a lint run over the same project hold the SAME `AppFile`
37
+ * instances, so each file is read and parsed at most once for both. The language server does
38
+ * that; check-node builds no graph, so merging into `nodeParsers` would do nothing.
39
+ *
40
+ * THE MCP SUPERVISOR DELIBERATELY DOES NOT SHARE, and this is not a pending to-do: it builds no
41
+ * graph, parsing per request only the handful of files that could reference the edited one.
42
+ * Routing those through check-node's shared `App` would win nothing — `lintBuffers` parses the
43
+ * content it was HANDED and drops the app's entry on the way out — and would risk something,
44
+ * because that `App` carries UNSAVED buffers while the blast radius runs CONCURRENTLY with the
45
+ * lint.
46
+ */
47
+ exports.graphParsers = {
48
+ extensions: {
49
+ js: parseJs,
50
+ ...Object.fromEntries(types_1.SUPPORTED_ASSET_IMAGE_EXTENSIONS.map((extension) => [extension, parseOpaqueAsset])),
51
+ },
52
+ };
53
+ /**
54
+ * A `getSourceCode` for the graph backed by an {@link App}.
55
+ *
56
+ * Pass it as `IDependencies.getSourceCode` and the graph stops parsing anything the
57
+ * lint has already parsed, and vice versa — they read the same file objects. Files
58
+ * the app does not contain fall through to `fallback`, which is how a URI outside
59
+ * the project (or an unclassified file) still gets a source code.
60
+ */
61
+ function appBackedGetSourceCode(app, fallback) {
62
+ return async (uri) => {
63
+ const file = app.get(uri);
64
+ if (!file)
65
+ return fallback(uri);
66
+ await file.load();
67
+ // An AppFile is structurally a SourceCode; its `ast` is typed `unknown` only
68
+ // because platformos-common sits below the parsers that produce ASTs.
69
+ return file;
70
+ };
71
+ }
72
+ //# sourceMappingURL=parsers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parsers.js","sourceRoot":"","sources":["../src/parsers.ts"],"names":[],"mappings":";;;AAOA,0BASC;AA8CD,wDAYC;AAzED,iFAA8D;AAC9D,iCAAqD;AAErD,mCAA2E;AAE3E,0FAA0F;AAC1F,SAAgB,OAAO,CAAC,MAAc;IACpC,IAAI,CAAC;QACH,OAAO,IAAA,aAAU,EAAC,MAAM,EAAE;YACxB,WAAW,EAAE,QAAQ;YACrB,UAAU,EAAE,QAAQ;SACrB,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,IAAA,iCAAO,EAAC,KAAK,CAAC,CAAC;IACxB,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,gBAAgB,GAAW,GAAG,EAAE,CAAC,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;AAEjF;;;;;;;;;;;;;;;;;;;GAmBG;AACU,QAAA,YAAY,GAAY;IACnC,UAAU,EAAE;QACV,EAAE,EAAE,OAAO;QACX,GAAG,MAAM,CAAC,WAAW,CACnB,wCAAgC,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC,CACnF;KACF;CACF,CAAC;AAEF;;;;;;;GAOG;AACH,SAAgB,sBAAsB,CACpC,GAAQ,EACR,QAAqD;IAErD,OAAO,KAAK,EAAE,GAAc,EAA2B,EAAE;QACvD,MAAM,IAAI,GAAwB,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC/C,IAAI,CAAC,IAAI;YAAE,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC;QAChC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,6EAA6E;QAC7E,sEAAsE;QACtE,OAAO,IAAiC,CAAC;IAC3C,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const platformos_common_1 = require("@platformos/platformos-common");
4
+ const platformos_check_common_1 = require("@platformos/platformos-check-common");
5
+ const vitest_1 = require("vitest");
6
+ const parsers_1 = require("./parsers");
7
+ const toSourceCode_1 = require("./toSourceCode");
8
+ const ROOT = 'file:///project';
9
+ const uri = (relativePath) => `${ROOT}/${relativePath}`;
10
+ const fsOver = (files) => ({
11
+ readFile: async (target) => {
12
+ const source = files[target];
13
+ if (source === undefined)
14
+ throw new Error(`ENOENT: ${target}`);
15
+ return source;
16
+ },
17
+ stat: async () => {
18
+ throw new Error('not used');
19
+ },
20
+ readDirectory: async () => [],
21
+ });
22
+ (0, vitest_1.describe)('graphParsers', () => {
23
+ (0, vitest_1.it)('registers a JS parser and treats images as opaque', async () => {
24
+ const jsUri = uri('app/assets/app.js');
25
+ const pngUri = uri('app/assets/logo.png');
26
+ const files = { [jsUri]: 'export const a = 1;', [pngUri]: 'binary' };
27
+ const app = platformos_common_1.App.fromPaths(ROOT, [jsUri, pngUri], fsOver(files), parsers_1.graphParsers);
28
+ await app.load();
29
+ (0, vitest_1.expect)(app.get(jsUri).ast.type).toBe('Program');
30
+ (0, vitest_1.expect)(app.get(pngUri).ast).toEqual(new Error('File parsing not implemented'));
31
+ });
32
+ (0, vitest_1.it)('is the same JS parse the buffer path uses', async () => {
33
+ const source = 'export const a = 1;';
34
+ const jsUri = uri('app/assets/app.js');
35
+ const app = platformos_common_1.App.fromPaths(ROOT, [jsUri], fsOver({ [jsUri]: source }), parsers_1.graphParsers);
36
+ await app.load();
37
+ const fromBuffer = await (0, toSourceCode_1.toSourceCode)(jsUri, source);
38
+ (0, vitest_1.expect)(app.get(jsUri).ast).toEqual(fromBuffer.ast);
39
+ });
40
+ });
41
+ (0, vitest_1.describe)('appBackedGetSourceCode', () => {
42
+ const parsers = (liquid = vitest_1.vi.fn(platformos_check_common_1.toLiquidHTMLAST)) => ({
43
+ parsers: { [platformos_common_1.SourceCodeType.LiquidHtml]: liquid, extensions: parsers_1.graphParsers.extensions },
44
+ liquid,
45
+ });
46
+ (0, vitest_1.it)('parses a file at most once across a graph read and a lint read', async () => {
47
+ const cardUri = uri('app/views/partials/card.liquid');
48
+ const { parsers: registered, liquid } = parsers();
49
+ const app = platformos_common_1.App.fromPaths(ROOT, [cardUri], fsOver({ [cardUri]: '<b>card</b>' }), registered);
50
+ const getSourceCode = (0, parsers_1.appBackedGetSourceCode)(app, async () => {
51
+ throw new Error('fallback should not be needed');
52
+ });
53
+ // The graph asks for it…
54
+ const forGraph = await getSourceCode(cardUri);
55
+ void forGraph.ast;
56
+ // …and the lint reads the same file object.
57
+ await app.get(cardUri).load();
58
+ void app.get(cardUri).ast;
59
+ (0, vitest_1.expect)(forGraph).toBe(app.get(cardUri));
60
+ (0, vitest_1.expect)(liquid.mock.calls.length).toBe(1);
61
+ });
62
+ (0, vitest_1.it)('falls back for a URI the app does not contain', async () => {
63
+ const app = platformos_common_1.App.fromPaths(ROOT, [], fsOver({}), parsers_1.graphParsers);
64
+ const outside = 'file:///elsewhere/thing.liquid';
65
+ const result = await (0, parsers_1.appBackedGetSourceCode)(app, async (target) => (0, toSourceCode_1.toSourceCode)(target, '<b>outside</b>'))(outside);
66
+ (0, vitest_1.expect)(result.uri).toBe(outside);
67
+ (0, vitest_1.expect)(result.source).toBe('<b>outside</b>');
68
+ });
69
+ });
70
+ //# sourceMappingURL=parsers.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parsers.spec.js","sourceRoot":"","sources":["../src/parsers.spec.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,17 @@
1
1
  import { UriString } from '@platformos/platformos-check-common';
2
- import { Program } from 'acorn';
3
2
  import { FileSourceCode } from './types';
4
- export declare function parseJs(source: string): Program | Error;
3
+ import { parseJs } from './parsers';
4
+ export { parseJs };
5
+ /**
6
+ * Build a source code for a graph node from contents already in hand.
7
+ *
8
+ * This is the path for callers with no `App`: an in-flight editor buffer, a fixture,
9
+ * a URI from outside the project. Callers that DO have one should pass
10
+ * `appBackedGetSourceCode(app, …)` as `getSourceCode` instead — that is what makes a
11
+ * graph build and a lint run share one parse per file rather than doing one each.
12
+ *
13
+ * The JS and image-asset parses come from {@link graphParsers}, so there is exactly
14
+ * one definition of how each is handled whether the file arrives through the App
15
+ * model or through here.
16
+ */
5
17
  export declare function toSourceCode(uri: UriString, source: string): Promise<FileSourceCode>;
@@ -1,31 +1,35 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseJs = parseJs;
3
+ exports.parseJs = void 0;
4
4
  exports.toSourceCode = toSourceCode;
5
5
  const platformos_check_common_1 = require("@platformos/platformos-check-common");
6
- const acorn_1 = require("acorn");
6
+ const platformos_common_1 = require("@platformos/platformos-common");
7
+ const parsers_1 = require("./parsers");
8
+ Object.defineProperty(exports, "parseJs", { enumerable: true, get: function () { return parsers_1.parseJs; } });
7
9
  const utils_1 = require("./utils");
8
- function parseJs(source) {
9
- try {
10
- return (0, acorn_1.parse)(source, {
11
- ecmaVersion: 'latest',
12
- sourceType: 'module',
13
- });
14
- }
15
- catch (error) {
16
- return (0, platformos_check_common_1.asError)(error);
17
- }
18
- }
10
+ /**
11
+ * Build a source code for a graph node from contents already in hand.
12
+ *
13
+ * This is the path for callers with no `App`: an in-flight editor buffer, a fixture,
14
+ * a URI from outside the project. Callers that DO have one should pass
15
+ * `appBackedGetSourceCode(app, …)` as `getSourceCode` instead — that is what makes a
16
+ * graph build and a lint run share one parse per file rather than doing one each.
17
+ *
18
+ * The JS and image-asset parses come from {@link graphParsers}, so there is exactly
19
+ * one definition of how each is handled whether the file arrives through the App
20
+ * model or through here.
21
+ */
19
22
  async function toSourceCode(uri, source) {
20
23
  const extension = (0, utils_1.extname)(uri);
21
- if (extension === 'json' ||
22
- extension === 'liquid' ||
23
- extension === 'graphql' ||
24
- extension === 'yml' ||
25
- extension === 'yaml') {
24
+ // `sourceCodeTypeOf` is the single answer to which extensions check-common
25
+ // parses; `.json` is the one addition, and only because `tcToSourceCode` models
26
+ // an unrecognised buffer as JSON for the editor (see its doc comment). Anything
27
+ // else is an asset, parsed — or not — by `graphParsers`.
28
+ if ((0, platformos_common_1.sourceCodeTypeOf)(uri) !== undefined || extension === 'json') {
26
29
  return (0, platformos_check_common_1.toSourceCode)(uri, source);
27
30
  }
28
- const ast = extension === 'js' ? parseJs(source) : new Error('File parsing not implemented');
31
+ const parse = parsers_1.graphParsers.extensions?.[extension];
32
+ const ast = (parse ? parse(source, uri) : new Error('File parsing not implemented'));
29
33
  const assetSourceCode = { type: 'asset', uri, source, ast };
30
34
  return assetSourceCode;
31
35
  }
@@ -1 +1 @@
1
- {"version":3,"file":"toSourceCode.js","sourceRoot":"","sources":["../src/toSourceCode.ts"],"names":[],"mappings":";;AASA,0BASC;AAED,oCAkBC;AAtCD,iFAI6C;AAC7C,iCAAqD;AAErD,mCAAkC;AAElC,SAAgB,OAAO,CAAC,MAAc;IACpC,IAAI,CAAC;QACH,OAAO,IAAA,aAAU,EAAC,MAAM,EAAE;YACxB,WAAW,EAAE,QAAQ;YACrB,UAAU,EAAE,QAAQ;SACrB,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,IAAA,iCAAO,EAAC,KAAK,CAAC,CAAC;IACxB,CAAC;AACH,CAAC;AAEM,KAAK,UAAU,YAAY,CAAC,GAAc,EAAE,MAAc;IAC/D,MAAM,SAAS,GAAG,IAAA,eAAO,EAAC,GAAG,CAAC,CAAC;IAE/B,IACE,SAAS,KAAK,MAAM;QACpB,SAAS,KAAK,QAAQ;QACtB,SAAS,KAAK,SAAS;QACvB,SAAS,KAAK,KAAK;QACnB,SAAS,KAAK,MAAM,EACpB,CAAC;QACD,OAAO,IAAA,sCAAc,EAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC;IAED,MAAM,GAAG,GACP,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAEnF,MAAM,eAAe,GAAoB,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IAC7E,OAAO,eAAe,CAAC;AACzB,CAAC"}
1
+ {"version":3,"file":"toSourceCode.js","sourceRoot":"","sources":["../src/toSourceCode.ts"],"names":[],"mappings":";;;AAoBA,oCAkBC;AAtCD,iFAAgG;AAChG,qEAAiE;AAEjE,uCAAkD;AAGzC,wFAHc,iBAAO,OAGd;AAFhB,mCAAkC;AAIlC;;;;;;;;;;;GAWG;AACI,KAAK,UAAU,YAAY,CAAC,GAAc,EAAE,MAAc;IAC/D,MAAM,SAAS,GAAG,IAAA,eAAO,EAAC,GAAG,CAAC,CAAC;IAE/B,2EAA2E;IAC3E,gFAAgF;IAChF,gFAAgF;IAChF,yDAAyD;IACzD,IAAI,IAAA,oCAAgB,EAAC,GAAG,CAAC,KAAK,SAAS,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;QAChE,OAAO,IAAA,sCAAc,EAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC;IAED,MAAM,KAAK,GAAG,sBAAY,CAAC,UAAU,EAAE,CAAC,SAAS,CAAC,CAAC;IACnD,MAAM,GAAG,GAAG,CACV,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAC7C,CAAC;IAE5B,MAAM,eAAe,GAAoB,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IAC7E,OAAO,eAAe,CAAC;AACzB,CAAC"}