@orkestrel/scaffold 0.0.9 → 0.0.11
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/dist/bin/scaffold.js +47 -21
- package/dist/bin/scaffold.js.map +1 -1
- package/dist/host/guides/src/scaffold.md +64 -29
- package/dist/host/tests/setupPolicy.ts +87 -2
- package/dist/src/core/index.cjs +78 -54
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +51 -21
- package/dist/src/core/index.d.ts +51 -21
- package/dist/src/core/index.js +77 -55
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +9 -3
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +2 -1
- package/dist/src/server/index.d.ts +2 -1
- package/dist/src/server/index.js +11 -5
- package/dist/src/server/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -134,7 +134,7 @@ From [`types.ts`](../../src/core/types.ts).
|
|
|
134
134
|
| `SrcDefinition` | interface |
|
|
135
135
|
| `AppDefinition` | interface |
|
|
136
136
|
| `ViteMachinery` | interface |
|
|
137
|
-
| `
|
|
137
|
+
| `ViteFacts` | interface |
|
|
138
138
|
| `ViteProjectRegistration` | interface |
|
|
139
139
|
| `Origin` | type |
|
|
140
140
|
| `Group` | type |
|
|
@@ -192,8 +192,10 @@ single-file-component, HTML, and development-server machinery an application bro
|
|
|
192
192
|
needs, and `output` for build-output containment. It never selects a boundary guarantee — those ship
|
|
193
193
|
in every shape, as the compilers section sets out.
|
|
194
194
|
|
|
195
|
-
`
|
|
196
|
-
`bin`, `integration`, and `service` each select their matching standalone project when `true
|
|
195
|
+
`ViteFacts` is the optional structural-fact slice shared by every root Vite compiler:
|
|
196
|
+
`bin`, `integration`, and `service` each select their matching standalone project when `true`;
|
|
197
|
+
`global` records the exact-case consumer-owned global-setup module and wires it into each eligible
|
|
198
|
+
project.
|
|
197
199
|
|
|
198
200
|
`ViteProjectRegistration` carries one generated project factory identifier and its optional browser
|
|
199
201
|
label. Root configuration renderers preserve that browser ownership as data through registration
|
|
@@ -217,6 +219,7 @@ interface Blueprint {
|
|
|
217
219
|
readonly bin: boolean
|
|
218
220
|
readonly integration: boolean
|
|
219
221
|
readonly service: boolean
|
|
222
|
+
readonly global: boolean
|
|
220
223
|
}
|
|
221
224
|
```
|
|
222
225
|
|
|
@@ -227,11 +230,11 @@ packages — a peer flagged `optional` also gets a `peerDependenciesMeta` entry.
|
|
|
227
230
|
package-specific development dependencies merged over the generated baseline, and may carry any
|
|
228
231
|
valid npm package name.
|
|
229
232
|
|
|
230
|
-
`bin`, `integration`, and `
|
|
231
|
-
`true` only when the workspace physically ships the directory
|
|
232
|
-
the workspace's name, and never because a sibling
|
|
233
|
-
those
|
|
234
|
-
workspace is.
|
|
233
|
+
`bin`, `integration`, `service`, and `global` are structural project facts. All four obey one law:
|
|
234
|
+
each is `true` only when the workspace physically ships the directory or exact-case file that
|
|
235
|
+
defines it — never because of the workspace's name, and never because a sibling fact is set.
|
|
236
|
+
`deriveBlueprint` probes those paths, so a fresh compile and an audit of a mature repository agree
|
|
237
|
+
on what the workspace is.
|
|
235
238
|
|
|
236
239
|
- **`bin`** — `src/bin/` exists. It alone turns on the self-hosting extras: the manifest's `bin`
|
|
237
240
|
entry, the `scaffold` script pointed at the built executable, the bin check, test, and build
|
|
@@ -245,6 +248,10 @@ workspace is.
|
|
|
245
248
|
running process, outside the default run: a standalone `service` project including
|
|
246
249
|
`tests/service/**/*.test.ts`, with `tests/setupService.ts` after the shared setup, and the
|
|
247
250
|
isolated `test:service` script.
|
|
251
|
+
- **`global`** — the physical, exact-case `tests/setupGlobal.ts` file exists. It is the single
|
|
252
|
+
governing setup-presence fact. A declared `src/browser` project runs that consumer-owned module
|
|
253
|
+
as `globalSetup`; integration runs it only when `bin` and `integration` are also true.
|
|
254
|
+
Application-browser, styles, service, and unrelated proof projects never receive it.
|
|
248
255
|
|
|
249
256
|
A service workspace owes two companion files beside that directory, and derivation requires both
|
|
250
257
|
physically present: `tests/setupService.ts` and `scripts/service.sh`. Either missing companion is a
|
|
@@ -360,6 +367,7 @@ From [`constants.ts`](../../src/core/constants.ts).
|
|
|
360
367
|
| `APP_MATRIX` | const |
|
|
361
368
|
| `HOST_PATHS` | const |
|
|
362
369
|
| `SERVICE_SCRIPT_PATH` | const |
|
|
370
|
+
| `GLOBAL_SETUP_PATH` | const |
|
|
363
371
|
| `NAME_PATTERN` | const |
|
|
364
372
|
| `MAX_NAME_LENGTH` | const |
|
|
365
373
|
| `MAX_DEPENDENCY_NAME_LENGTH` | const |
|
|
@@ -410,7 +418,8 @@ axis's computed `tsconfig` and Vite wrapper pair. `HOST_PATHS` is the ordered li
|
|
|
410
418
|
host artifacts, and it is the staging manifest rather than the per-plan carried set:
|
|
411
419
|
`stageHost` vendors every path on it, while each plan carries the subset `selectHostPaths` selects
|
|
412
420
|
for that one workspace. `SERVICE_SCRIPT_PATH` names the consumer-owned provisioner a service
|
|
413
|
-
workspace's audit expects
|
|
421
|
+
workspace's audit expects, and `GLOBAL_SETUP_PATH` names the consumer-owned Vitest global-setup
|
|
422
|
+
module that independently selected projects can load.
|
|
414
423
|
|
|
415
424
|
The bounds are public because they are part of the contract, not implementation trivia.
|
|
416
425
|
`MAX_ARTIFACT_BYTES` caps one artifact at 5 MiB and `MAX_TOTAL_ARTIFACT_BYTES` caps one blueprint,
|
|
@@ -789,6 +798,7 @@ From [`helpers.ts`](../../src/core/helpers.ts).
|
|
|
789
798
|
| `stableStringify` | function |
|
|
790
799
|
| `planPayload` | function |
|
|
791
800
|
| `computeColumnWidth` | function |
|
|
801
|
+
| `fitsPrintWidth` | function |
|
|
792
802
|
| `renderArray` | function |
|
|
793
803
|
| `renderObject` | function |
|
|
794
804
|
| `renderValue` | function |
|
|
@@ -800,10 +810,11 @@ own data descriptor, so parsed JSON cannot acquire manifest fields through a pol
|
|
|
800
810
|
and accessors are never invoked. Each builder omits an absent optional
|
|
801
811
|
field entirely rather than writing `undefined`, so a built value round-trips its own exact-record
|
|
802
812
|
guard. `blueprint` fills the defaults: `version` and `engines` from their constants, `src` to
|
|
803
|
-
`['core']`,
|
|
804
|
-
lowercase-hyphen package name, and `blueprintToMembers` derives the
|
|
805
|
-
full entity, options type, interface, and factory per published
|
|
806
|
-
inventory each selected application environment
|
|
813
|
+
`['core']`, every other collection to empty, and every structural fact to `false`. `pascalCase`
|
|
814
|
+
derives the entity name from a lowercase-hyphen package name, and `blueprintToMembers` derives the
|
|
815
|
+
declared public `Member[]` — a full entity, options type, interface, and factory per published
|
|
816
|
+
environment, plus the exact declaration inventory each selected application environment
|
|
817
|
+
contributes.
|
|
807
818
|
|
|
808
819
|
`escapeHtmlText` and `serializeTypeScriptString` are the two escaping leaves used when a
|
|
809
820
|
caller-supplied name reaches generated HTML or generated TypeScript source; the latter preserves
|
|
@@ -853,7 +864,7 @@ marks an empty axis). `PlanManager` compares the canonical payload whenever an
|
|
|
853
864
|
id is already registered: an identical plan is idempotent, while a distinct payload with the same
|
|
854
865
|
32-bit digest fails closed with `ScaffoldError('INVALID', 'Plan hash collision')`.
|
|
855
866
|
`formatJson` and its leaves — `renderValue`,
|
|
856
|
-
`renderArray`, `renderObject`, and `
|
|
867
|
+
`renderArray`, `renderObject`, `computeColumnWidth`, and `fitsPrintWidth` — emit JSON that matches the fleet
|
|
857
868
|
formatter byte for byte, collapsing a short array onto one line and breaking a long one, so
|
|
858
869
|
computed configuration JSON is format-stable by construction.
|
|
859
870
|
|
|
@@ -949,10 +960,11 @@ omitting an absent path entirely. `readManifest` reads `package.json` text, and
|
|
|
949
960
|
|
|
950
961
|
`deriveBlueprint` is the faithful inverse an audit needs: it reconstructs a blueprint from an
|
|
951
962
|
existing workspace so a mature package is diffed against its own would-be scaffold rather than a
|
|
952
|
-
dependency-less stand-in. Environments come from `src/<environment>/` and `app/<environment>/`,
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
963
|
+
dependency-less stand-in. Environments come from `src/<environment>/` and `app/<environment>/`, the
|
|
964
|
+
three structural project facts from their directory probes, and `global` from the physical,
|
|
965
|
+
exact-case `tests/setupGlobal.ts` file; the service companion law remains the one the blueprint
|
|
966
|
+
section states — every fact is a reading of the filesystem, never of the name. Dependencies and peers come
|
|
967
|
+
from the manifest's scoped entries, with an optional peer recovered from
|
|
956
968
|
`peerDependenciesMeta`; and `extras` is every development dependency minus the complete set
|
|
957
969
|
`devDependenciesFor` emits for those environments and structural axes, and minus anything already
|
|
958
970
|
declared as a dependency or peer. An axis-emitted dependency is therefore never double-counted,
|
|
@@ -1095,13 +1107,17 @@ without output containment — and it still carries every boundary guarantee abo
|
|
|
1095
1107
|
|
|
1096
1108
|
`renderViteTest` is the single root-project renderer. It consumes ordered `ViteProjectRegistration`
|
|
1097
1109
|
data and emits either the plain project list or the browser gate, keeping source and application
|
|
1098
|
-
root configurations byte-consistent without reconstructing browser ownership.
|
|
1110
|
+
root configurations byte-consistent without reconstructing browser ownership. Both forms use the
|
|
1111
|
+
formatter's 100-column fixed point: a complete registration-array line, including indentation and
|
|
1112
|
+
its trailing comma, stays collapsed when it fits and expands one entry per line otherwise.
|
|
1099
1113
|
`viteProjectRegistrations` is the one registration derivation every root shape consumes: it derives
|
|
1100
1114
|
the selected source and application projects from the canonical environment order, then appends
|
|
1101
1115
|
`policy`, `guides`, and the optional `srcBin`, `integration`, and `service` projects.
|
|
1102
|
-
`viteProjectDefinitions` renders the standalone proof and structural-
|
|
1103
|
-
order with one blank line between declarations. Both consume `
|
|
1104
|
-
controlled only by its matching `bin`, `integration`, or `service` blueprint
|
|
1116
|
+
`viteProjectDefinitions` renders the standalone proof and structural-fact definitions in that same
|
|
1117
|
+
order with one blank line between declarations. Both consume `ViteFacts`, so each optional project
|
|
1118
|
+
is controlled only by its matching `bin`, `integration`, or `service` blueprint fact; the same
|
|
1119
|
+
slice carries `global` to integration and the source-browser compiler without adding another
|
|
1120
|
+
project.
|
|
1105
1121
|
|
|
1106
1122
|
`coreViteConfig`, `srcViteConfig`, `binViteConfig`, and `appViteConfig` emit the thin per-target
|
|
1107
1123
|
wrappers, while `binTsconfig` emits the executable declaration scope; `rootViteConfig`,
|
|
@@ -1115,9 +1131,12 @@ or application environment project. The guides project therefore uses only `test
|
|
|
1115
1131
|
`tests/app/**/*.test.ts` exclude rows are uniform across all root shapes by design, including
|
|
1116
1132
|
core-only workspaces where one row cannot currently match. Integration and service use 120-second
|
|
1117
1133
|
test and hook timeouts with file parallelism disabled, and service alone layers
|
|
1118
|
-
`tests/setupService.ts` onto the shared setup.
|
|
1119
|
-
|
|
1120
|
-
|
|
1134
|
+
`tests/setupService.ts` onto the shared setup. The integration project wires
|
|
1135
|
+
`tests/setupGlobal.ts` for the shared template-registry harness exactly when `bin`, `integration`,
|
|
1136
|
+
and `global` are all true. Independently, a `global` source-browser project places
|
|
1137
|
+
`globalSetup: ['./tests/setupGlobal.ts']` immediately before its ordinary `setupFiles` row (and
|
|
1138
|
+
after the core-test exclusion where that row exists). Application browser projects never receive
|
|
1139
|
+
that field.
|
|
1121
1140
|
|
|
1122
1141
|
`configArtifacts`, `sourceArtifacts`, `applicationArtifacts`, `testArtifacts`, and `guideArtifacts`
|
|
1123
1142
|
are the per-group drafters. When `bin` is selected, `configArtifacts` includes
|
|
@@ -1666,9 +1685,14 @@ readonly, that privacy is a runtime `#` field rather than a TypeScript modifier,
|
|
|
1666
1685
|
re-exports only through `export *`, that a core source never names a worker-only global the
|
|
1667
1686
|
`WebWorker` declarations expose, and that a computed dynamic import cannot smuggle a
|
|
1668
1687
|
cross-environment dependency past the declared import rules. Vue components are inspected for the
|
|
1669
|
-
same evasions.
|
|
1670
|
-
|
|
1671
|
-
|
|
1688
|
+
same evasions. A self-contained runtime entrypoint may be exempt from module-scope placement only
|
|
1689
|
+
when it is not a centralized kind file and has at least one real `node:` value import. Erased
|
|
1690
|
+
type-only imports may reference sibling contracts; any non-`node:` static value import,
|
|
1691
|
+
`export … from` re-export, or dynamic `import(...)` disqualifies the exemption. An importless file
|
|
1692
|
+
does not qualify, and centralized declarations remain subject to their export law. Every other
|
|
1693
|
+
policy law still applies. It is a complement to lint and typecheck, never a second type system, and
|
|
1694
|
+
it is not a general-purpose source analyzer. Generated workspaces receive the same exported policy
|
|
1695
|
+
module as a host-origin file and run it as a dedicated Node-only `policy` test project over
|
|
1672
1696
|
`tests/policy.test.ts`.
|
|
1673
1697
|
|
|
1674
1698
|
**Real browser capability.** Browser test projects are gated on the real executable: the generated
|
|
@@ -1683,6 +1707,15 @@ Node projects. One printed warning names every gated project label. A machine wi
|
|
|
1683
1707
|
registers and runs the real browser suites unchanged; a machine without one runs the remaining
|
|
1684
1708
|
projects and says so.
|
|
1685
1709
|
|
|
1710
|
+
**Consumer-owned global setup.** The single mechanism-named `tests/setupGlobal.ts` module may
|
|
1711
|
+
prepare a shared integration registry, a real Node-side counterpart for source-browser tests such
|
|
1712
|
+
as a WebSocket fixture server, or both. The scaffold does not emit or replace it. Derivation
|
|
1713
|
+
records its exact-case physical presence as `global`, the single governing fact. Integration
|
|
1714
|
+
consumes it only when `bin` and `integration` are also true; a declared `src/browser` independently
|
|
1715
|
+
wires it to `srcBrowser`. Removing the file removes both eligible rows from regenerated
|
|
1716
|
+
configuration byte-for-byte. Application browser, styles, and service readiness setup remain
|
|
1717
|
+
isolated from this seam.
|
|
1718
|
+
|
|
1686
1719
|
**Continuous integration.** The generated workflow runs on push and pull request, on
|
|
1687
1720
|
`ubuntu-latest`, with read-only contents permission, a 60-minute timeout, and a matrix that **tests
|
|
1688
1721
|
Node `22.12.0` and `26`** with fail-fast disabled. Checkout and Node setup are pinned to immutable
|
|
@@ -1981,6 +2014,7 @@ import {
|
|
|
1981
2014
|
compareCodeUnit,
|
|
1982
2015
|
computeColumnWidth,
|
|
1983
2016
|
escapeHtmlText,
|
|
2017
|
+
fitsPrintWidth,
|
|
1984
2018
|
formatJson,
|
|
1985
2019
|
renderArray,
|
|
1986
2020
|
renderObject,
|
|
@@ -1993,6 +2027,7 @@ renderValue('ESNext', '', '', '') // '"ESNext"'
|
|
|
1993
2027
|
renderArray(['ESNext', 'DOM'], '', '', '') // '["ESNext", "DOM"]'
|
|
1994
2028
|
renderObject({ lib: ['ESNext'] }, '') // '{\n\t"lib": ["ESNext"]\n}'
|
|
1995
2029
|
computeColumnWidth('\t"a"') // 3
|
|
2030
|
+
fitsPrintWidth('\t["ESNext"],') // true
|
|
1996
2031
|
|
|
1997
2032
|
escapeHtmlText('<app & "team">') // '<app & "team">'
|
|
1998
2033
|
serializeTypeScriptString("app's") // "'app\\'s'"
|
|
@@ -2172,7 +2207,7 @@ appViteConfig('server')
|
|
|
2172
2207
|
policyViteProject()
|
|
2173
2208
|
guidesViteProject()
|
|
2174
2209
|
binViteProject()
|
|
2175
|
-
integrationViteProject({ bin: true, integration: true })
|
|
2210
|
+
integrationViteProject({ bin: true, integration: true, global: true })
|
|
2176
2211
|
serviceViteProject()
|
|
2177
2212
|
viteProjectDefinitions({ integration: true }).includes('export const integration =') // true
|
|
2178
2213
|
viteProjectRegistrations(['core'], [], { integration: true }).map(({ project }) => project)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { globSync, readFileSync } from 'node:fs'
|
|
2
|
+
import { isBuiltin } from 'node:module'
|
|
2
3
|
import { basename, join } from 'node:path'
|
|
3
4
|
import * as ts from 'typescript'
|
|
4
5
|
|
|
@@ -199,6 +200,77 @@ export function hasAllowedTripleSlashReference(path: string, source: ts.SourceFi
|
|
|
199
200
|
)
|
|
200
201
|
}
|
|
201
202
|
|
|
203
|
+
/**
|
|
204
|
+
* Whether a source is self-contained around a positively identified Node runtime dependency.
|
|
205
|
+
*
|
|
206
|
+
* @param source - The parsed source file to inspect.
|
|
207
|
+
* @returns `true` when at least one value import names a real `node:` builtin and no sibling,
|
|
208
|
+
* re-exported, or dynamic runtime dependency is present; type-only imports are erased.
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* ```ts
|
|
212
|
+
* const source = ts.createSourceFile(
|
|
213
|
+
* 'serve.ts',
|
|
214
|
+
* "import { parentPort } from 'node:worker_threads'",
|
|
215
|
+
* ts.ScriptTarget.Latest,
|
|
216
|
+
* true,
|
|
217
|
+
* )
|
|
218
|
+
* isSelfContained(source) // true
|
|
219
|
+
* ```
|
|
220
|
+
*/
|
|
221
|
+
export function isSelfContained(source: ts.SourceFile): boolean {
|
|
222
|
+
const pending: ts.Node[] = [source]
|
|
223
|
+
while (pending.length > 0) {
|
|
224
|
+
const node = pending.pop()
|
|
225
|
+
if (node === undefined) continue
|
|
226
|
+
if (ts.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword) {
|
|
227
|
+
return false
|
|
228
|
+
}
|
|
229
|
+
ts.forEachChild(node, (child) => {
|
|
230
|
+
pending.push(child)
|
|
231
|
+
})
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
let builtin = false
|
|
235
|
+
for (const statement of source.statements) {
|
|
236
|
+
if (ts.isExportDeclaration(statement) && statement.moduleSpecifier !== undefined) {
|
|
237
|
+
return false
|
|
238
|
+
}
|
|
239
|
+
if (ts.isImportDeclaration(statement)) {
|
|
240
|
+
const clause = statement.importClause
|
|
241
|
+
const named = clause?.namedBindings
|
|
242
|
+
const erased =
|
|
243
|
+
clause?.isTypeOnly === true ||
|
|
244
|
+
(clause !== undefined &&
|
|
245
|
+
clause.name === undefined &&
|
|
246
|
+
named !== undefined &&
|
|
247
|
+
ts.isNamedImports(named) &&
|
|
248
|
+
named.elements.length > 0 &&
|
|
249
|
+
named.elements.every((element) => element.isTypeOnly))
|
|
250
|
+
if (erased) continue
|
|
251
|
+
if (!ts.isStringLiteral(statement.moduleSpecifier)) return false
|
|
252
|
+
const specifier = statement.moduleSpecifier.text
|
|
253
|
+
if (!specifier.startsWith('node:') || !isBuiltin(specifier)) return false
|
|
254
|
+
builtin = true
|
|
255
|
+
}
|
|
256
|
+
if (ts.isImportEqualsDeclaration(statement)) {
|
|
257
|
+
if (statement.isTypeOnly) continue
|
|
258
|
+
const reference = statement.moduleReference
|
|
259
|
+
if (
|
|
260
|
+
!ts.isExternalModuleReference(reference) ||
|
|
261
|
+
reference.expression === undefined ||
|
|
262
|
+
!ts.isStringLiteral(reference.expression)
|
|
263
|
+
) {
|
|
264
|
+
return false
|
|
265
|
+
}
|
|
266
|
+
const specifier = reference.expression.text
|
|
267
|
+
if (!specifier.startsWith('node:') || !isBuiltin(specifier)) return false
|
|
268
|
+
builtin = true
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return builtin
|
|
272
|
+
}
|
|
273
|
+
|
|
202
274
|
/**
|
|
203
275
|
* Whether the policy compiler can read one source path.
|
|
204
276
|
*
|
|
@@ -425,6 +497,11 @@ export function inspectCodingLaw(path: string, content: string): readonly string
|
|
|
425
497
|
if (source === undefined) throw new Error(`Policy source was not bound at ${path}`)
|
|
426
498
|
const checker = program.getTypeChecker()
|
|
427
499
|
const file = basename(path)
|
|
500
|
+
const placementExempt =
|
|
501
|
+
!CENTRAL_SOURCE_FILES.includes(file) &&
|
|
502
|
+
!FUNCTION_SOURCE_FILES.includes(file) &&
|
|
503
|
+
!DATA_SOURCE_FILES.includes(file) &&
|
|
504
|
+
isSelfContained(source)
|
|
428
505
|
|
|
429
506
|
if (/\.[cm]?jsx?$/u.test(path)) {
|
|
430
507
|
violations.push(`${path} production modules use TypeScript source extensions`)
|
|
@@ -472,10 +549,18 @@ export function inspectCodingLaw(path: string, content: string): readonly string
|
|
|
472
549
|
) {
|
|
473
550
|
violations.push(`${path} exports every centralized declaration`)
|
|
474
551
|
}
|
|
475
|
-
if (
|
|
552
|
+
if (
|
|
553
|
+
!placementExempt &&
|
|
554
|
+
ts.isFunctionDeclaration(statement) &&
|
|
555
|
+
!FUNCTION_SOURCE_FILES.includes(file)
|
|
556
|
+
) {
|
|
476
557
|
violations.push(`${path} places module functions in their centralized kind file`)
|
|
477
558
|
}
|
|
478
|
-
if (
|
|
559
|
+
if (
|
|
560
|
+
!placementExempt &&
|
|
561
|
+
ts.isVariableStatement(statement) &&
|
|
562
|
+
!DATA_SOURCE_FILES.includes(file)
|
|
563
|
+
) {
|
|
479
564
|
violations.push(`${path} places module data in its centralized kind file`)
|
|
480
565
|
}
|
|
481
566
|
if (
|