@platformos/platformos-graph 0.0.20 → 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 (120) hide show
  1. package/CHANGELOG.md +511 -8
  2. package/dist/cache-probes.spec.d.ts +1 -0
  3. package/dist/cache-probes.spec.js +62 -0
  4. package/dist/cache-probes.spec.js.map +1 -0
  5. package/dist/cli.js +18 -13
  6. package/dist/cli.js.map +1 -1
  7. package/dist/cli.spec.d.ts +1 -0
  8. package/dist/cli.spec.js +235 -0
  9. package/dist/cli.spec.js.map +1 -0
  10. package/dist/graph/app-index-resolution.spec.d.ts +1 -0
  11. package/dist/graph/app-index-resolution.spec.js +167 -0
  12. package/dist/graph/app-index-resolution.spec.js.map +1 -0
  13. package/dist/graph/asset-resolution.spec.d.ts +1 -0
  14. package/dist/graph/asset-resolution.spec.js +64 -0
  15. package/dist/graph/asset-resolution.spec.js.map +1 -0
  16. package/dist/graph/augment.js +3 -0
  17. package/dist/graph/augment.js.map +1 -1
  18. package/dist/graph/build.d.ts +15 -2
  19. package/dist/graph/build.js +54 -12
  20. package/dist/graph/build.js.map +1 -1
  21. package/dist/graph/build.spec.d.ts +1 -0
  22. package/dist/graph/build.spec.js +138 -0
  23. package/dist/graph/build.spec.js.map +1 -0
  24. package/dist/graph/edge-sources.d.ts +28 -0
  25. package/dist/graph/edge-sources.js +43 -0
  26. package/dist/graph/edge-sources.js.map +1 -0
  27. package/dist/graph/edge-sources.spec.d.ts +1 -0
  28. package/dist/graph/edge-sources.spec.js +125 -0
  29. package/dist/graph/edge-sources.spec.js.map +1 -0
  30. package/dist/graph/extract.spec.d.ts +1 -0
  31. package/dist/graph/extract.spec.js +163 -0
  32. package/dist/graph/extract.spec.js.map +1 -0
  33. package/dist/graph/module.d.ts +60 -7
  34. package/dist/graph/module.js +137 -41
  35. package/dist/graph/module.js.map +1 -1
  36. package/dist/graph/module.spec.d.ts +1 -0
  37. package/dist/graph/module.spec.js +74 -0
  38. package/dist/graph/module.spec.js.map +1 -0
  39. package/dist/graph/query.d.ts +72 -0
  40. package/dist/graph/query.js +140 -0
  41. package/dist/graph/query.js.map +1 -0
  42. package/dist/graph/query.spec.d.ts +1 -0
  43. package/dist/graph/query.spec.js +209 -0
  44. package/dist/graph/query.spec.js.map +1 -0
  45. package/dist/graph/serialize.spec.d.ts +1 -0
  46. package/dist/graph/serialize.spec.js +50 -0
  47. package/dist/graph/serialize.spec.js.map +1 -0
  48. package/dist/graph/structural.spec.d.ts +1 -0
  49. package/dist/graph/structural.spec.js +146 -0
  50. package/dist/graph/structural.spec.js.map +1 -0
  51. package/dist/graph/test-helpers.js +3 -3
  52. package/dist/graph/test-helpers.js.map +1 -1
  53. package/dist/graph/traverse-edges.spec.d.ts +1 -0
  54. package/dist/graph/traverse-edges.spec.js +337 -0
  55. package/dist/graph/traverse-edges.spec.js.map +1 -0
  56. package/dist/graph/traverse.d.ts +51 -20
  57. package/dist/graph/traverse.js +239 -29
  58. package/dist/graph/traverse.js.map +1 -1
  59. package/dist/index.d.ts +5 -1
  60. package/dist/index.js +19 -1
  61. package/dist/index.js.map +1 -1
  62. package/dist/parsers.d.ts +35 -0
  63. package/dist/parsers.js +72 -0
  64. package/dist/parsers.js.map +1 -0
  65. package/dist/parsers.spec.d.ts +1 -0
  66. package/dist/parsers.spec.js +70 -0
  67. package/dist/parsers.spec.js.map +1 -0
  68. package/dist/toSourceCode.d.ts +14 -2
  69. package/dist/toSourceCode.js +23 -19
  70. package/dist/toSourceCode.js.map +1 -1
  71. package/dist/tsconfig.tsbuildinfo +1 -1
  72. package/dist/types.d.ts +102 -3
  73. package/dist/types.js.map +1 -1
  74. package/dist/utils/index.d.ts +1 -1
  75. package/fixtures/asset-edges/app/assets/logo.css +1 -0
  76. package/fixtures/asset-edges/app/assets/site/app.js +1 -0
  77. package/fixtures/asset-edges/app/views/pages/index.liquid +3 -0
  78. package/fixtures/graphql-table/app/graphql/with_table.graphql +5 -0
  79. package/fixtures/graphql-table/app/graphql/without_table.graphql +3 -0
  80. package/fixtures/graphql-table/app/views/pages/index.liquid +4 -0
  81. package/fixtures/layout-edges/app/views/layouts/theme.liquid +4 -0
  82. package/fixtures/layout-edges/app/views/pages/broken.liquid +5 -0
  83. package/fixtures/layout-edges/app/views/pages/index.liquid +5 -0
  84. package/fixtures/schema-nodes/app/schema/blog_post.yml +6 -0
  85. package/fixtures/schema-nodes/app/schema/no_name.yml +3 -0
  86. package/fixtures/schema-nodes/app/views/pages/index.liquid +1 -0
  87. package/fixtures/structural/app/views/pages/about.liquid +1 -0
  88. package/fixtures/structural/app/views/pages/blog/show.liquid +4 -0
  89. package/fixtures/structural/app/views/pages/index.liquid +6 -0
  90. package/fixtures/structural/app/views/pages/rich.liquid +8 -0
  91. package/fixtures/structural/app/views/partials/card.liquid +1 -0
  92. package/fixtures/structural/app/views/partials/documented.liquid +5 -0
  93. package/package.json +7 -5
  94. package/src/cli.spec.ts +37 -31
  95. package/src/cli.ts +31 -15
  96. package/src/graph/augment.ts +4 -0
  97. package/src/graph/build.spec.ts +871 -6
  98. package/src/graph/build.ts +68 -17
  99. package/src/graph/edge-sources.spec.ts +125 -0
  100. package/src/graph/edge-sources.ts +49 -0
  101. package/src/graph/module.spec.ts +168 -0
  102. package/src/graph/module.ts +139 -45
  103. package/src/graph/query.spec.ts +260 -0
  104. package/src/graph/query.ts +154 -0
  105. package/src/graph/serialize.spec.ts +4 -4
  106. package/src/graph/test-helpers.ts +3 -3
  107. package/src/graph/{extract.spec.ts → traverse.spec.ts} +125 -2
  108. package/src/graph/traverse.ts +278 -37
  109. package/src/index.ts +16 -1
  110. package/src/parsers.spec.ts +85 -0
  111. package/src/parsers.ts +75 -0
  112. package/src/toSourceCode.ts +26 -26
  113. package/src/types.ts +106 -7
  114. package/src/utils/index.ts +1 -1
  115. package/dist/getWebComponentMap.d.ts +0 -10
  116. package/dist/getWebComponentMap.js +0 -66
  117. package/dist/getWebComponentMap.js.map +0 -1
  118. package/src/graph/traverse-edges.spec.ts +0 -278
  119. /package/fixtures/skeleton/{assets → app/assets}/app.css +0 -0
  120. /package/fixtures/skeleton/{assets → app/assets}/app.js +0 -0
@@ -1,3 +1,16 @@
1
1
  import { UriString } from '@platformos/platformos-check-common';
2
- import { IDependencies, AppGraph } from '../types';
3
- export declare function buildAppGraph(rootUri: UriString, ideps: IDependencies, entryPoints?: UriString[]): Promise<AppGraph>;
2
+ import { IDependencies, AppGraph, GraphBuildOptions } from '../types';
3
+ /**
4
+ * Build the project dependency graph.
5
+ *
6
+ * - `entryPoints` omitted → FULL build: a single directory sweep discovers pages
7
+ * + layouts (the render entry points) and standalone custom-model-type/schema
8
+ * nodes, and every reachable module is materialized.
9
+ * - `entryPoints` provided → SCOPED build (e.g. an LSP rebuild for changed
10
+ * files): built verbatim from those roots. Schema nodes are NOT auto-discovered
11
+ * in this mode — schema discovery is a full-build concern.
12
+ *
13
+ * `options.includeStructural` (default off) additionally populates each
14
+ * `LiquidModule.structural`; see {@link GraphBuildOptions}.
15
+ */
16
+ export declare function buildAppGraph(rootUri: UriString, ideps: IDependencies, entryPoints?: UriString[], options?: GraphBuildOptions): Promise<AppGraph>;
@@ -1,21 +1,60 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.buildAppGraph = buildAppGraph;
4
- const platformos_check_common_1 = require("@platformos/platformos-check-common");
4
+ const platformos_common_1 = require("@platformos/platformos-common");
5
5
  const augment_1 = require("./augment");
6
6
  const module_1 = require("./module");
7
7
  const traverse_1 = require("./traverse");
8
- async function buildAppGraph(rootUri, ideps, entryPoints) {
8
+ /**
9
+ * Build the project dependency graph.
10
+ *
11
+ * - `entryPoints` omitted → FULL build: a single directory sweep discovers pages
12
+ * + layouts (the render entry points) and standalone custom-model-type/schema
13
+ * nodes, and every reachable module is materialized.
14
+ * - `entryPoints` provided → SCOPED build (e.g. an LSP rebuild for changed
15
+ * files): built verbatim from those roots. Schema nodes are NOT auto-discovered
16
+ * in this mode — schema discovery is a full-build concern.
17
+ *
18
+ * `options.includeStructural` (default off) additionally populates each
19
+ * `LiquidModule.structural`; see {@link GraphBuildOptions}.
20
+ */
21
+ async function buildAppGraph(rootUri, ideps, entryPoints, options = {}) {
9
22
  const deps = (0, augment_1.augmentDependencies)(rootUri, ideps);
10
- entryPoints =
11
- entryPoints ??
12
- (await (0, platformos_check_common_1.recursiveReadDirectory)(deps.fs, rootUri, ([uri]) => {
13
- if (!uri.endsWith('.liquid'))
14
- return false;
15
- // Layouts are entry points — they wrap all page content.
16
- // Pages are also entry points — they are directly requested.
17
- return (0, platformos_check_common_1.isLayout)(uri) || (0, platformos_check_common_1.isPage)(uri);
18
- }));
23
+ // Table (schema / custom-model-type) files are platform nodes but are NOT
24
+ // render-reachable — nothing renders them — so they never appear via edge traversal. On
25
+ // a full build they are discovered as standalone leaf nodes, never entry points, so
26
+ // reachability/orphan semantics for the render graph are unaffected.
27
+ let schemaUris = [];
28
+ // An explicit entryPoints scope is built verbatim (e.g. a scoped LSP rebuild); the
29
+ // default full build (`entryPoints === undefined`) also discovers standalone Table
30
+ // nodes. Branching on the parameter directly lets the compiler narrow it below.
31
+ if (entryPoints === undefined) {
32
+ // ONE sweep yields both populations, partitioned by SourceCodeType below, so the
33
+ // tree is walked once. `walkAppSourceFiles` is anchored on APP_SOURCE_SUBTREES: the
34
+ // walk it replaces started at the root and skipped directories by NAME, which both
35
+ // dropped `app/views/pages/vendor/**` (a live site section — 137 files on one real
36
+ // project) and admitted `tmp/app/views/partials/x.liquid`.
37
+ const discovered = await (0, platformos_common_1.walkAppSourceFiles)(deps.fs, rootUri, ([uri]) => {
38
+ // Root-ANCHORED classification. The unanchored `getFileType(uri)` this used to call
39
+ // matched a known directory anywhere in the path, so
40
+ // `seed/post_import/app/migrations/x.liquid` classified as a Migration while being
41
+ // correctly absent from the lint's app.
42
+ const fileType = (0, platformos_common_1.getFileType)(uri, rootUri);
43
+ // A GRAPH-domain restriction, not a second answer to "what is a source file":
44
+ // Liquid is the only source that can reference another file, so a non-Liquid entry
45
+ // point would have no edges to traverse. Which extensions ARE Liquid still comes
46
+ // from platformos-common, never spelled here — which is also why the `.yml`/`.yaml`
47
+ // tests that used to partition this sweep are gone: `.yaml` is not a platformOS
48
+ // extension at all, so spelling it here promised coverage the platform never had.
49
+ if ((0, platformos_common_1.sourceCodeTypeOf)(uri) === platformos_common_1.SourceCodeType.LiquidHtml) {
50
+ // Layouts wrap all page content; pages are directly requested — both are entry points.
51
+ return fileType === platformos_common_1.PlatformOSFileType.Layout || fileType === platformos_common_1.PlatformOSFileType.Page;
52
+ }
53
+ return fileType === platformos_common_1.PlatformOSFileType.Table;
54
+ });
55
+ entryPoints = discovered.filter((uri) => (0, platformos_common_1.sourceCodeTypeOf)(uri) === platformos_common_1.SourceCodeType.LiquidHtml);
56
+ schemaUris = discovered.filter((uri) => (0, platformos_common_1.sourceCodeTypeOf)(uri) !== platformos_common_1.SourceCodeType.LiquidHtml);
57
+ }
19
58
  const graph = {
20
59
  entryPoints: [],
21
60
  modules: {},
@@ -24,7 +63,10 @@ async function buildAppGraph(rootUri, ideps, entryPoints) {
24
63
  graph.entryPoints = entryPoints
25
64
  .map((uri) => (0, module_1.getModule)(graph, uri))
26
65
  .filter((x) => x !== undefined);
27
- await Promise.all(graph.entryPoints.map((entry) => (0, traverse_1.traverseModule)(entry, graph, deps)));
66
+ await Promise.all(graph.entryPoints.map((entry) => (0, traverse_1.traverseModule)(entry, graph, deps, options)));
67
+ if (schemaUris.length > 0) {
68
+ await Promise.all(schemaUris.map((uri) => (0, traverse_1.traverseModule)((0, module_1.getSchemaModule)(graph, uri), graph, deps, options)));
69
+ }
28
70
  return graph;
29
71
  }
30
72
  //# sourceMappingURL=build.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/graph/build.ts"],"names":[],"mappings":";;AAYA,sCA6BC;AAzCD,iFAM6C;AAE7C,uCAAgD;AAChD,qCAAqC;AACrC,yCAA4C;AAErC,KAAK,UAAU,aAAa,CACjC,OAAkB,EAClB,KAAoB,EACpB,WAAyB;IAEzB,MAAM,IAAI,GAAG,IAAA,6BAAmB,EAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAEjD,WAAW;QACT,WAAW;YACX,CAAC,MAAM,IAAA,gDAAY,EAAC,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE;gBAC9C,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC;oBAAE,OAAO,KAAK,CAAC;gBAC3C,yDAAyD;gBACzD,6DAA6D;gBAC7D,OAAO,IAAA,kCAAQ,EAAC,GAAG,CAAC,IAAI,IAAA,gCAAM,EAAC,GAAG,CAAC,CAAC;YACtC,CAAC,CAAC,CAAC,CAAC;IAEN,MAAM,KAAK,GAAa;QACtB,WAAW,EAAE,EAAE;QACf,OAAO,EAAE,EAAE;QACX,OAAO;KACR,CAAC;IAEF,KAAK,CAAC,WAAW,GAAG,WAAW;SAC5B,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAA,kBAAS,EAAC,KAAK,EAAE,GAAG,CAAC,CAAC;SACnC,MAAM,CAAC,CAAC,CAAC,EAAkB,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;IAElD,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAA,yBAAc,EAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAExF,OAAO,KAAK,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/graph/build.ts"],"names":[],"mappings":";;AA0BA,sCAkEC;AA3FD,qEAMuC;AAEvC,uCAAgD;AAChD,qCAAsD;AACtD,yCAA4C;AAE5C;;;;;;;;;;;;GAYG;AACI,KAAK,UAAU,aAAa,CACjC,OAAkB,EAClB,KAAoB,EACpB,WAAyB,EACzB,UAA6B,EAAE;IAE/B,MAAM,IAAI,GAAG,IAAA,6BAAmB,EAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAEjD,0EAA0E;IAC1E,wFAAwF;IACxF,oFAAoF;IACpF,qEAAqE;IACrE,IAAI,UAAU,GAAgB,EAAE,CAAC;IAEjC,mFAAmF;IACnF,mFAAmF;IACnF,gFAAgF;IAChF,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9B,iFAAiF;QACjF,oFAAoF;QACpF,mFAAmF;QACnF,mFAAmF;QACnF,2DAA2D;QAC3D,MAAM,UAAU,GAAG,MAAM,IAAA,sCAAkB,EAAC,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE;YACtE,oFAAoF;YACpF,qDAAqD;YACrD,mFAAmF;YACnF,wCAAwC;YACxC,MAAM,QAAQ,GAAG,IAAA,+BAAW,EAAC,GAAG,EAAE,OAAO,CAAC,CAAC;YAE3C,8EAA8E;YAC9E,mFAAmF;YACnF,iFAAiF;YACjF,oFAAoF;YACpF,gFAAgF;YAChF,kFAAkF;YAClF,IAAI,IAAA,oCAAgB,EAAC,GAAG,CAAC,KAAK,kCAAc,CAAC,UAAU,EAAE,CAAC;gBACxD,uFAAuF;gBACvF,OAAO,QAAQ,KAAK,sCAAkB,CAAC,MAAM,IAAI,QAAQ,KAAK,sCAAkB,CAAC,IAAI,CAAC;YACxF,CAAC;YACD,OAAO,QAAQ,KAAK,sCAAkB,CAAC,KAAK,CAAC;QAC/C,CAAC,CAAC,CAAC;QAEH,WAAW,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAA,oCAAgB,EAAC,GAAG,CAAC,KAAK,kCAAc,CAAC,UAAU,CAAC,CAAC;QAC9F,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAA,oCAAgB,EAAC,GAAG,CAAC,KAAK,kCAAc,CAAC,UAAU,CAAC,CAAC;IAC/F,CAAC;IAED,MAAM,KAAK,GAAa;QACtB,WAAW,EAAE,EAAE;QACf,OAAO,EAAE,EAAE;QACX,OAAO;KACR,CAAC;IAEF,KAAK,CAAC,WAAW,GAAG,WAAW;SAC5B,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAA,kBAAS,EAAC,KAAK,EAAE,GAAG,CAAC,CAAC;SACnC,MAAM,CAAC,CAAC,CAAC,EAAkB,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;IAElD,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAA,yBAAc,EAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAEjG,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,OAAO,CAAC,GAAG,CACf,UAAU,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAA,yBAAc,EAAC,IAAA,wBAAe,EAAC,KAAK,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAC3F,CAAC;IACJ,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const platformos_check_common_1 = require("@platformos/platformos-check-common");
4
+ const test_1 = require("@platformos/platformos-check-common/src/test");
5
+ const vitest_1 = require("vitest");
6
+ const index_1 = require("../index");
7
+ const toSourceCode_1 = require("../toSourceCode");
8
+ const test_helpers_1 = require("./test-helpers");
9
+ (0, vitest_1.describe)('Module: index', () => {
10
+ const rootUri = test_helpers_1.skeleton;
11
+ const p = (part) => platformos_check_common_1.path.join(rootUri, ...part.split('/'));
12
+ const loc = (part) => vitest_1.expect.objectContaining({ uri: p(part) });
13
+ let dependencies;
14
+ (0, vitest_1.beforeAll)(async () => {
15
+ dependencies = (0, test_helpers_1.getDependencies)();
16
+ }, 15000);
17
+ (0, vitest_1.describe)('Unit: buildAppGraph', { timeout: 10000 }, () => {
18
+ (0, vitest_1.it)('builds a graph of the app', { timeout: 10000 }, async () => {
19
+ const graph = await (0, index_1.buildAppGraph)(rootUri, dependencies);
20
+ (0, vitest_1.expect)(graph).toBeDefined();
21
+ });
22
+ (0, vitest_1.describe)('with a valid app graph', () => {
23
+ let graph;
24
+ (0, vitest_1.beforeEach)(async () => {
25
+ graph = await (0, index_1.buildAppGraph)(rootUri, dependencies);
26
+ });
27
+ (0, vitest_1.it)('has a root URI', () => {
28
+ (0, vitest_1.expect)(graph.rootUri).toBeDefined();
29
+ (0, vitest_1.expect)(graph.rootUri).toBe(rootUri);
30
+ });
31
+ (0, vitest_1.it)('infers entry points from layouts and pages', () => {
32
+ (0, vitest_1.expect)(graph.entryPoints).toHaveLength(2);
33
+ (0, vitest_1.expect)(graph.entryPoints.map((x) => x.uri)).toEqual(vitest_1.expect.arrayContaining([
34
+ p('app/views/layouts/application.liquid'),
35
+ p('app/views/pages/index.liquid'),
36
+ ]));
37
+ });
38
+ (0, vitest_1.it)("finds app/views/layouts/application.liquid's dependencies", () => {
39
+ const layout = graph.modules[p('app/views/layouts/application.liquid')];
40
+ (0, vitest_1.assert)(layout);
41
+ (0, vitest_1.assert)(layout.type === "Liquid" /* ModuleType.Liquid */);
42
+ (0, vitest_1.assert)(layout.kind === "layout" /* LiquidModuleKind.Layout */);
43
+ const deps = layout.dependencies;
44
+ (0, vitest_1.expect)(deps.map((x) => x.target.uri)).toEqual(vitest_1.expect.arrayContaining([
45
+ p('app/assets/app.js'),
46
+ p('app/assets/app.css'),
47
+ p('app/views/partials/header.liquid'),
48
+ ]));
49
+ });
50
+ (0, vitest_1.it)("finds app/views/partials/parent's dependencies and references", async () => {
51
+ const parentPartial = graph.modules[p('app/views/partials/parent.liquid')];
52
+ (0, vitest_1.assert)(parentPartial);
53
+ (0, vitest_1.assert)(parentPartial.type === "Liquid" /* ModuleType.Liquid */);
54
+ (0, vitest_1.assert)(parentPartial.kind === "partial" /* LiquidModuleKind.Partial */);
55
+ // outgoing links — parent renders exactly one partial (child)
56
+ const deps = parentPartial.dependencies;
57
+ (0, vitest_1.assert)(deps.map((x) => x.source.uri).every((x) => x === parentPartial.uri));
58
+ (0, vitest_1.expect)(deps.map((x) => x.target.uri)).toEqual([p('app/views/partials/child.liquid')]);
59
+ // {% render 'child' %} dependency
60
+ const parentSource = await dependencies.getSourceCode(p('app/views/partials/parent.liquid'));
61
+ (0, vitest_1.assert)(parentSource);
62
+ (0, vitest_1.assert)(parentSource.type === platformos_check_common_1.SourceCodeType.LiquidHtml);
63
+ (0, vitest_1.expect)(parentPartial.dependencies.map((x) => x.source)).toContainEqual(vitest_1.expect.objectContaining({
64
+ uri: p('app/views/partials/parent.liquid'),
65
+ range: [
66
+ parentSource.source.indexOf('{% render "child"'),
67
+ parentSource.source.indexOf('{% render "child"') +
68
+ '{% render "child", children: children %}'.length,
69
+ ],
70
+ }));
71
+ });
72
+ (0, vitest_1.it)("finds app/views/partials/child's references", () => {
73
+ const childPartial = graph.modules[p('app/views/partials/child.liquid')];
74
+ (0, vitest_1.assert)(childPartial);
75
+ (0, vitest_1.assert)(childPartial.type === "Liquid" /* ModuleType.Liquid */);
76
+ (0, vitest_1.assert)(childPartial.kind === "partial" /* LiquidModuleKind.Partial */);
77
+ const refs = childPartial.references;
78
+ (0, vitest_1.expect)(refs.map((x) => x.source.uri)).toEqual(vitest_1.expect.arrayContaining([
79
+ p('app/views/partials/parent.liquid'),
80
+ p('app/views/partials/header.liquid'),
81
+ ]));
82
+ });
83
+ (0, vitest_1.it)('tags every layout edge with its kind (asset, asset, render)', () => {
84
+ const layout = graph.modules[p('app/views/layouts/application.liquid')];
85
+ (0, vitest_1.assert)(layout);
86
+ // The complete, ordered edge set — not a membership probe — so an extra,
87
+ // missing, or mis-kinded edge fails. (Source ranges are pinned by the
88
+ // dedicated render-dependency test above.)
89
+ (0, vitest_1.expect)(layout.dependencies.map((d) => ({ target: d.target.uri, type: d.type, kind: d.kind }))).toEqual([
90
+ { target: p('app/assets/app.js'), type: 'direct', kind: 'asset' },
91
+ { target: p('app/assets/app.css'), type: 'direct', kind: 'asset' },
92
+ { target: p('app/views/partials/header.liquid'), type: 'direct', kind: 'render' },
93
+ ]);
94
+ });
95
+ });
96
+ /**
97
+ * Entry points come from an ANCHORED walk of the app subtrees, so what a
98
+ * directory is CALLED never decides whether the graph can see it. The walk this
99
+ * replaced skipped any directory ending in `vendor`, `build`, `tmp` or `dist`,
100
+ * which lost every page under `app/views/pages/vendor/**` — a real section of a
101
+ * real site — while still descending into `tmp/app/views/pages/`, which the
102
+ * platform does not deploy at all.
103
+ */
104
+ (0, vitest_1.describe)('entry points on a project with app directories named like build output', () => {
105
+ const projectRoot = 'file:///project';
106
+ const u = (part) => `${projectRoot}/${part}`;
107
+ let graph;
108
+ (0, vitest_1.beforeEach)(async () => {
109
+ const fs = new test_1.MockFileSystem({
110
+ 'app/views/pages/vendor/index.liquid': `{% render 'vendor/card' %}`,
111
+ 'app/views/pages/build/status.liquid': `ok`,
112
+ 'app/views/partials/vendor/card.liquid': `a card`,
113
+ 'tmp/app/views/pages/scratch.liquid': `not deployed`,
114
+ 'node_modules/some-pkg/app/views/pages/decoy.liquid': `not ours`,
115
+ 'dist/app/views/pages/bundled.liquid': `build output`,
116
+ }, projectRoot);
117
+ graph = await (0, index_1.buildAppGraph)(projectRoot, {
118
+ fs,
119
+ getSourceCode: async (uri) => (0, toSourceCode_1.toSourceCode)(uri, await fs.readFile(uri)),
120
+ });
121
+ });
122
+ (0, vitest_1.it)('finds the pages under vendor/ and build/, and nothing outside the app subtrees', () => {
123
+ (0, vitest_1.expect)(graph.entryPoints.map((entry) => entry.uri).sort()).toEqual([
124
+ u('app/views/pages/build/status.liquid'),
125
+ u('app/views/pages/vendor/index.liquid'),
126
+ ]);
127
+ });
128
+ (0, vitest_1.it)('traverses them, so a partial under vendor/ is a graph node with a reference', () => {
129
+ const card = graph.modules[u('app/views/partials/vendor/card.liquid')];
130
+ (0, vitest_1.assert)(card);
131
+ (0, vitest_1.expect)(card.references.map((reference) => reference.source.uri)).toEqual([
132
+ u('app/views/pages/vendor/index.liquid'),
133
+ ]);
134
+ });
135
+ });
136
+ });
137
+ });
138
+ //# sourceMappingURL=build.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.spec.js","sourceRoot":"","sources":["../../src/graph/build.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { type UriString } from '@platformos/platformos-check-common';
2
+ import { type AbstractFileSystem } from '@platformos/platformos-common';
3
+ /**
4
+ * The canonical definition of an EDGE SOURCE: a liquid file whose own content can declare
5
+ * outgoing edges (a Page, Layout, or Partial). Only these files' add/remove/modify can change
6
+ * any file's set of dependents — `.graphql`/`.yml`/asset files are leaves.
7
+ *
8
+ * "Which files" derives entirely from the file-type classifier, so this predicate never
9
+ * re-encodes the classification. It is ANCHORED on `rootUri`, because a file's type IS its
10
+ * position relative to the project root: unanchored, `tmp/app/lib/x.liquid` is a Partial.
11
+ */
12
+ export declare function isEdgeSource(uri: UriString, rootUri: UriString): boolean;
13
+ /**
14
+ * Enumerate every edge-source liquid file under a project root — the single canonical primitive
15
+ * for "which files are the graph's edge sources". Consumers never re-derive the walk or the
16
+ * {@link isEdgeSource} predicate.
17
+ *
18
+ * The walk is `walkAppSourceFiles`, platformos-common's anchored expansion of
19
+ * `APP_SOURCE_SUBTREES`, so this file names no directory at all and a bundled `react-app/` is
20
+ * never walked. `edge-sources.spec` pins the scoped result against a whole-tree walk filtered
21
+ * by {@link isEdgeSource}.
22
+ *
23
+ * NOT shared with `buildAppGraph`'s full-build discovery: the two gather DIFFERENT domains —
24
+ * that one takes render entry points (pages + layouts, partials being edge-reached) plus
25
+ * standalone schema nodes, this one takes page + layout + partial. They share the walk
26
+ * primitive and the classifier, which are the parts that must not drift.
27
+ */
28
+ export declare function enumerateEdgeSources(fs: AbstractFileSystem, rootUri: UriString): Promise<UriString[]>;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isEdgeSource = isEdgeSource;
4
+ exports.enumerateEdgeSources = enumerateEdgeSources;
5
+ const platformos_common_1 = require("@platformos/platformos-common");
6
+ /**
7
+ * The canonical definition of an EDGE SOURCE: a liquid file whose own content can declare
8
+ * outgoing edges (a Page, Layout, or Partial). Only these files' add/remove/modify can change
9
+ * any file's set of dependents — `.graphql`/`.yml`/asset files are leaves.
10
+ *
11
+ * "Which files" derives entirely from the file-type classifier, so this predicate never
12
+ * re-encodes the classification. It is ANCHORED on `rootUri`, because a file's type IS its
13
+ * position relative to the project root: unanchored, `tmp/app/lib/x.liquid` is a Partial.
14
+ */
15
+ function isEdgeSource(uri, rootUri) {
16
+ switch ((0, platformos_common_1.getFileType)(uri, rootUri)) {
17
+ case platformos_common_1.PlatformOSFileType.Layout:
18
+ case platformos_common_1.PlatformOSFileType.Page:
19
+ case platformos_common_1.PlatformOSFileType.Partial:
20
+ return true;
21
+ default:
22
+ return false;
23
+ }
24
+ }
25
+ /**
26
+ * Enumerate every edge-source liquid file under a project root — the single canonical primitive
27
+ * for "which files are the graph's edge sources". Consumers never re-derive the walk or the
28
+ * {@link isEdgeSource} predicate.
29
+ *
30
+ * The walk is `walkAppSourceFiles`, platformos-common's anchored expansion of
31
+ * `APP_SOURCE_SUBTREES`, so this file names no directory at all and a bundled `react-app/` is
32
+ * never walked. `edge-sources.spec` pins the scoped result against a whole-tree walk filtered
33
+ * by {@link isEdgeSource}.
34
+ *
35
+ * NOT shared with `buildAppGraph`'s full-build discovery: the two gather DIFFERENT domains —
36
+ * that one takes render entry points (pages + layouts, partials being edge-reached) plus
37
+ * standalone schema nodes, this one takes page + layout + partial. They share the walk
38
+ * primitive and the classifier, which are the parts that must not drift.
39
+ */
40
+ async function enumerateEdgeSources(fs, rootUri) {
41
+ return (0, platformos_common_1.walkAppSourceFiles)(fs, rootUri, ([uri]) => isEdgeSource(uri, rootUri));
42
+ }
43
+ //# sourceMappingURL=edge-sources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edge-sources.js","sourceRoot":"","sources":["../../src/graph/edge-sources.ts"],"names":[],"mappings":";;AAiBA,oCASC;AAiBD,oDAKC;AA/CD,qEAKuC;AAEvC;;;;;;;;GAQG;AACH,SAAgB,YAAY,CAAC,GAAc,EAAE,OAAkB;IAC7D,QAAQ,IAAA,+BAAW,EAAC,GAAG,EAAE,OAAO,CAAC,EAAE,CAAC;QAClC,KAAK,sCAAkB,CAAC,MAAM,CAAC;QAC/B,KAAK,sCAAkB,CAAC,IAAI,CAAC;QAC7B,KAAK,sCAAkB,CAAC,OAAO;YAC7B,OAAO,IAAI,CAAC;QACd;YACE,OAAO,KAAK,CAAC;IACjB,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACI,KAAK,UAAU,oBAAoB,CACxC,EAAsB,EACtB,OAAkB;IAElB,OAAO,IAAA,sCAAkB,EAAC,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;AAChF,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const platformos_check_common_1 = require("@platformos/platformos-check-common");
5
+ const platformos_common_1 = require("@platformos/platformos-common");
6
+ const test_1 = require("@platformos/platformos-check-common/dist/test");
7
+ const index_1 = require("../index");
8
+ /**
9
+ * TASK-9.17: `enumerateEdgeSources` is the SINGLE canonical "what are the
10
+ * edge-source liquid files under a project root" primitive. The supervisor's
11
+ * GraphCache consumes it for BOTH the fingerprint domain and the build's entry
12
+ * points, so its definition must never silently drift from the file-type
13
+ * classifier (`getFileType` ← `FILE_TYPE_DIRS`).
14
+ *
15
+ * The load-bearing guard is EQUIVALENCE-TO-THE-CLASSIFIER: the SCOPED walk (only
16
+ * `APP_SOURCE_SUBTREES`, the TASK-9.15 Phase-3A perf win) must gather the exact
17
+ * same set a WHOLE-TREE walk filtered by `isEdgeSource` would. If a partial
18
+ * location is added to the classifier but its subtree is not walkable, the
19
+ * whole-tree walk finds files the scoped walk misses → this test fails, catching
20
+ * the drift before it under-reports dependents.
21
+ */
22
+ (0, vitest_1.describe)('Unit: enumerateEdgeSources (canonical edge-source enumeration)', () => {
23
+ const rootUri = platformos_check_common_1.path.normalize('file:/');
24
+ const uri = (rel) => platformos_check_common_1.path.join(rootUri, rel);
25
+ // Edge sources under every canonical location a Page/Layout/Partial can live.
26
+ const EDGE_SOURCES = [
27
+ 'app/views/pages/home.liquid', // Page (modern app/ root)
28
+ 'app/views/layouts/application.liquid', // Layout
29
+ 'app/views/partials/card.liquid', // Partial (views/partials)
30
+ 'app/lib/helper.liquid', // Partial (lib)
31
+ 'marketplace_builder/views/pages/legacy.liquid', // Page (legacy root)
32
+ 'modules/shop/public/views/partials/widget.liquid', // Partial (top-level module, public)
33
+ 'modules/shop/private/lib/secret.liquid', // Partial (top-level module, PRIVATE access level)
34
+ 'app/modules/blog/private/views/pages/post.liquid', // Page (nested app/modules)
35
+ ];
36
+ // Files that are NOT edge sources: leaves, non-liquid, and a bundled
37
+ // non-platformOS sibling that must never be walked.
38
+ const NON_EDGE_SOURCES = {
39
+ 'app/graphql/get_posts.graphql': 'query { records { results { id } } }',
40
+ 'app/schema/blog_post.yml': 'name: blog_post',
41
+ 'app/assets/logo.css': 'body {}',
42
+ 'react-app/src/components/Widget.liquid': 'noise that is never a source',
43
+ 'README.md': '# project',
44
+ };
45
+ const makeFs = () => {
46
+ const files = { ...NON_EDGE_SOURCES };
47
+ for (const rel of EDGE_SOURCES)
48
+ files[rel] = '<div></div>';
49
+ return new test_1.MockFileSystem(files, rootUri);
50
+ };
51
+ const sorted = (uris) => [...uris].sort();
52
+ (0, vitest_1.it)('gathers exactly the edge sources across all source roots (nothing else)', async () => {
53
+ const fs = makeFs();
54
+ (0, vitest_1.expect)(sorted(await (0, index_1.enumerateEdgeSources)(fs, rootUri))).toEqual(sorted(EDGE_SOURCES.map(uri)));
55
+ });
56
+ (0, vitest_1.it)('the scoped walk equals a whole-tree walk filtered by the classifier (no drift)', async () => {
57
+ const fs = makeFs();
58
+ const scoped = sorted(await (0, index_1.enumerateEdgeSources)(fs, rootUri));
59
+ const wholeTree = sorted((await everyFileUnder(fs, rootUri)).filter((u) => (0, index_1.isEdgeSource)(u, rootUri)));
60
+ (0, vitest_1.expect)(scoped).toEqual(wholeTree);
61
+ });
62
+ (0, vitest_1.it)('isEdgeSource is exactly the Layout/Page/Partial classification', () => {
63
+ const EDGE_SOURCE_TYPES = [
64
+ platformos_common_1.PlatformOSFileType.Layout,
65
+ platformos_common_1.PlatformOSFileType.Page,
66
+ platformos_common_1.PlatformOSFileType.Partial,
67
+ ];
68
+ for (const rel of EDGE_SOURCES) {
69
+ const u = uri(rel);
70
+ (0, vitest_1.expect)((0, index_1.isEdgeSource)(u, rootUri)).toBe(true);
71
+ (0, vitest_1.expect)(EDGE_SOURCE_TYPES).toContain((0, platformos_common_1.getFileType)(u, rootUri));
72
+ }
73
+ for (const rel of Object.keys(NON_EDGE_SOURCES)) {
74
+ const u = uri(rel);
75
+ (0, vitest_1.expect)((0, index_1.isEdgeSource)(u, rootUri)).toBe(false);
76
+ (0, vitest_1.expect)(EDGE_SOURCE_TYPES).not.toContain((0, platformos_common_1.getFileType)(u, rootUri));
77
+ }
78
+ });
79
+ /**
80
+ * The reason the classification is anchored on the root. Unanchored, a directory
81
+ * named like a platformOS one ANYWHERE in the path classified: these three files
82
+ * are not part of the app, and counting them in the fingerprint domain made the
83
+ * supervisor's GraphCache rebuild on edits to files the app never reads.
84
+ */
85
+ (0, vitest_1.it)('does not admit a platformOS-looking path outside the app subtrees', async () => {
86
+ const outside = {
87
+ 'tmp/app/views/partials/scratch.liquid': '<div></div>',
88
+ 'seed/post_import/app/views/pages/fixture.liquid': '<div></div>',
89
+ 'node_modules/pkg/app/lib/helper.liquid': '<div></div>',
90
+ };
91
+ for (const rel of Object.keys(outside))
92
+ (0, vitest_1.expect)((0, index_1.isEdgeSource)(uri(rel), rootUri)).toBe(false);
93
+ // Control: the same three spellings ARE found when they sit at the real root, so
94
+ // the silence above is the anchoring, not the fixture or the walk.
95
+ const files = { ...outside };
96
+ for (const rel of EDGE_SOURCES)
97
+ files[rel] = '<div></div>';
98
+ const fs = new test_1.MockFileSystem(files, rootUri);
99
+ (0, vitest_1.expect)(sorted(await (0, index_1.enumerateEdgeSources)(fs, rootUri))).toEqual(sorted(EDGE_SOURCES.map(uri)));
100
+ });
101
+ (0, vitest_1.it)('never yields a non-platformOS sibling (a bundled react-app/ is skipped)', async () => {
102
+ const fs = makeFs();
103
+ const result = await (0, index_1.enumerateEdgeSources)(fs, rootUri);
104
+ (0, vitest_1.expect)(result).not.toContain(uri('react-app/src/components/Widget.liquid'));
105
+ });
106
+ });
107
+ /**
108
+ * Every file under `baseUri`, by brute-force recursion into every directory.
109
+ *
110
+ * Deliberately written HERE, and deliberately NOT `walkAppSourceFiles`: that is the walk
111
+ * `enumerateEdgeSources` is built on, so using it for the control too would compare the
112
+ * mechanism against itself and the equivalence assertion above would hold no matter how
113
+ * wrong `APP_SOURCE_SUBTREES` became. An independent walk is the entire value of that test.
114
+ *
115
+ * (It replaces check-common's `recursiveReadDirectory`, which master removed from
116
+ * production once the anchored walk superseded it. Its only remaining purpose was to be
117
+ * this control, and a control belongs next to the test that needs it rather than in a
118
+ * shipped package's public API.)
119
+ */
120
+ async function everyFileUnder(fs, baseUri) {
121
+ const entries = await fs.readDirectory(baseUri).catch(() => []);
122
+ const nested = await Promise.all(entries.map(async ([uri, type]) => type === platformos_common_1.FileType.Directory ? everyFileUnder(fs, uri) : [uri]));
123
+ return nested.flat();
124
+ }
125
+ //# sourceMappingURL=edge-sources.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edge-sources.spec.js","sourceRoot":"","sources":["../../src/graph/edge-sources.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};