driftdetect-vscode 0.9.32 → 0.9.34

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.
@@ -87,7 +87,7 @@ export class StateManager implements vscode.Disposable {
87
87
  this.listeners.add(listener);
88
88
 
89
89
  return {
90
- dispose: () => {
90
+ dispose: (): void => {
91
91
  this.listeners.delete(listener);
92
92
  },
93
93
  };
@@ -99,7 +99,7 @@ export class StateManager implements vscode.Disposable {
99
99
  subscribeAll(callback: (state: ExtensionState) => void): vscode.Disposable {
100
100
  this.listeners.add(callback);
101
101
  return {
102
- dispose: () => {
102
+ dispose: (): void => {
103
103
  this.listeners.delete(callback);
104
104
  },
105
105
  };
@@ -130,8 +130,8 @@ export class StateManager implements vscode.Disposable {
130
130
  for (const listener of this.listeners) {
131
131
  try {
132
132
  listener(this.state);
133
- } catch (error) {
134
- console.error('[Drift] State listener error:', error);
133
+ } catch {
134
+ // Listener error, continue with others
135
135
  }
136
136
  }
137
137
  }
@@ -141,7 +141,7 @@ export class StateManager implements vscode.Disposable {
141
141
 
142
142
  try {
143
143
  const persisted = this.context.globalState.get<Partial<ExtensionState>>(PERSISTENCE_KEY);
144
- if (persisted) {
144
+ if (persisted?.preferences !== undefined) {
145
145
  // Only restore preferences, not transient state
146
146
  return {
147
147
  ...initial,
@@ -151,8 +151,8 @@ export class StateManager implements vscode.Disposable {
151
151
  },
152
152
  };
153
153
  }
154
- } catch (error) {
155
- console.error('[Drift] Failed to load persisted state:', error);
154
+ } catch {
155
+ // Failed to load persisted state, use initial
156
156
  }
157
157
 
158
158
  return initial;
@@ -164,10 +164,7 @@ export class StateManager implements vscode.Disposable {
164
164
  preferences: this.state.preferences,
165
165
  };
166
166
 
167
- this.context.globalState.update(PERSISTENCE_KEY, toPersist).then(
168
- () => {},
169
- (error) => { console.error('[Drift] Failed to persist state:', error); }
170
- );
167
+ void this.context.globalState.update(PERSISTENCE_KEY, toPersist);
171
168
  }
172
169
 
173
170
  private shallowEqual(a: unknown, b: unknown): boolean {
@@ -53,6 +53,6 @@ export interface DisposableManager {
53
53
  */
54
54
  export interface ServiceContainer {
55
55
  get<T>(key: string): T;
56
- register<T>(key: string, instance: T): void;
56
+ register(key: string, instance: unknown): void;
57
57
  has(key: string): boolean;
58
58
  }
@@ -33,8 +33,6 @@ export class DecorationController implements vscode.Disposable {
33
33
  * Update decorations for the active editor
34
34
  */
35
35
  updateDecorations(editor: vscode.TextEditor): void {
36
- if (!editor) {return;}
37
-
38
36
  const uri = editor.document.uri;
39
37
  const diagnostics = vscode.languages.getDiagnostics(uri);
40
38
 
@@ -187,7 +185,7 @@ export class DecorationController implements vscode.Disposable {
187
185
 
188
186
  for (const d of diagnostics) {
189
187
  const severity = this.diagnosticSeverityToString(d.severity);
190
- const group = groups.get(severity) || [];
188
+ const group = groups.get(severity) ?? [];
191
189
  group.push(d);
192
190
  groups.set(severity, group);
193
191
  }
@@ -216,8 +214,9 @@ export class DecorationController implements vscode.Disposable {
216
214
  const icon = this.getSeverityIcon(diagnostic.severity);
217
215
  md.appendMarkdown(`${icon} **${diagnostic.message}**\n\n`);
218
216
 
219
- if (diagnostic.code) {
220
- md.appendMarkdown(`Pattern: \`${diagnostic.code}\`\n\n`);
217
+ if (diagnostic.code !== null) {
218
+ const codeStr = typeof diagnostic.code === 'object' ? String(diagnostic.code.value) : String(diagnostic.code);
219
+ md.appendMarkdown(`Pattern: \`${codeStr}\`\n\n`);
221
220
  }
222
221
 
223
222
  md.appendMarkdown(`---\n\n`);
@@ -97,7 +97,7 @@ export class NotificationService {
97
97
  const pickOptions: vscode.QuickPickOptions = {
98
98
  ...options,
99
99
  };
100
- if (options.title) {
100
+ if (options.title !== null && options.title !== '') {
101
101
  pickOptions.title = `Drift: ${options.title}`;
102
102
  }
103
103
  return vscode.window.showQuickPick(items, pickOptions);
@@ -110,7 +110,7 @@ export class NotificationService {
110
110
  const inputOptions: vscode.InputBoxOptions = {
111
111
  ...options,
112
112
  };
113
- if (options.title) {
113
+ if (options.title !== null && options.title !== '') {
114
114
  inputOptions.title = `Drift: ${options.title}`;
115
115
  }
116
116
  return vscode.window.showInputBox(inputOptions);
@@ -134,7 +134,7 @@ export class NotificationService {
134
134
  if (options.modal !== undefined) {
135
135
  messageOptions.modal = options.modal;
136
136
  }
137
- if (options.detail !== undefined) {
137
+ if (options.detail !== null && options.detail !== '' && options.detail !== undefined) {
138
138
  messageOptions.detail = options.detail;
139
139
  }
140
140
 
@@ -144,13 +144,13 @@ export class NotificationService {
144
144
  ...actionTitles
145
145
  );
146
146
 
147
- if (selected) {
147
+ if (selected !== null && selected !== '') {
148
148
  const action = actions.find(a => a.title === selected);
149
149
  if (action) {
150
150
  if (action.callback) {
151
151
  await action.callback();
152
152
  } else if (action.command) {
153
- await vscode.commands.executeCommand(action.command, ...(action.args || []));
153
+ await vscode.commands.executeCommand(action.command, ...(action.args ?? []));
154
154
  }
155
155
  }
156
156
  }
@@ -89,15 +89,15 @@ export class StatusBarController implements vscode.Disposable {
89
89
  // Add stats if connected
90
90
  if (state.connection.status === 'connected') {
91
91
  md.appendMarkdown(`---\n\n`);
92
- md.appendMarkdown(`**Patterns:** ${state.patterns.total}\n\n`);
93
- md.appendMarkdown(`**Violations:** ${state.violations.total}\n\n`);
92
+ md.appendMarkdown(`**Patterns:** ${String(state.patterns.total)}\n\n`);
93
+ md.appendMarkdown(`**Violations:** ${String(state.violations.total)}\n\n`);
94
94
 
95
95
  if (state.violations.total > 0) {
96
96
  md.appendMarkdown(`\n`);
97
97
  for (const [severity, count] of Object.entries(state.violations.bySeverity)) {
98
98
  if (count > 0) {
99
99
  const icon = this.getSeverityIcon(severity);
100
- md.appendMarkdown(`- ${icon} ${severity}: ${count}\n`);
100
+ md.appendMarkdown(`- ${icon} ${severity}: ${String(count)}\n`);
101
101
  }
102
102
  }
103
103
  }
@@ -90,30 +90,45 @@ export function getStatusBarMode(
90
90
  ): StatusBarMode {
91
91
  // Connection states take priority
92
92
  if (connectionState !== 'connected') {
93
- return StatusBarModes[connectionState] ?? StatusBarModes['disconnected']!;
93
+ const mode = StatusBarModes[connectionState];
94
+ return mode ?? StatusBarModes['disconnected'] ?? {
95
+ icon: '$(circle-slash)',
96
+ text: 'Drift: Disconnected',
97
+ tooltip: 'Drift is not connected.',
98
+ };
94
99
  }
95
100
 
96
101
  // Scanning state
97
102
  if (scanning) {
98
- return StatusBarModes['scanning']!;
103
+ const scanningMode = StatusBarModes['scanning'];
104
+ return scanningMode ?? {
105
+ icon: '$(sync~spin)',
106
+ text: 'Drift: Scanning...',
107
+ tooltip: 'Scanning workspace for patterns...',
108
+ };
99
109
  }
100
110
 
101
111
  // Violation-based states
102
112
  if (violations > 0) {
103
- const warningMode = StatusBarModes['warning']!;
113
+ const warningMode = StatusBarModes['warning'];
104
114
  const result: StatusBarMode = {
105
- icon: warningMode.icon,
106
- text: `Drift: ${violations}`,
107
- tooltip: `${violations} violation${violations === 1 ? '' : 's'} found. Click to view.`,
115
+ icon: warningMode?.icon ?? '$(warning)',
116
+ text: `Drift: ${String(violations)}`,
117
+ tooltip: `${String(violations)} violation${violations === 1 ? '' : 's'} found. Click to view.`,
108
118
  };
109
- if (warningMode.backgroundColor) {
119
+ if (warningMode?.backgroundColor) {
110
120
  result.backgroundColor = warningMode.backgroundColor;
111
121
  }
112
- if (warningMode.command) {
122
+ if (warningMode?.command) {
113
123
  result.command = warningMode.command;
114
124
  }
115
125
  return result;
116
126
  }
117
127
 
118
- return StatusBarModes['healthy']!;
128
+ const healthyMode = StatusBarModes['healthy'];
129
+ return healthyMode ?? {
130
+ icon: '$(pass)',
131
+ text: 'Drift',
132
+ tooltip: 'No violations found.',
133
+ };
119
134
  }
@@ -102,10 +102,6 @@ export interface ConstantTreeItem extends BaseTreeItem {
102
102
  export class ConstantsTreeProvider extends BaseTreeProvider<ConstantTreeItem> {
103
103
  private viewMode: 'category' | 'language' | 'issues' = 'category';
104
104
 
105
- constructor(client: LanguageClient | null) {
106
- super(client);
107
- }
108
-
109
105
  /**
110
106
  * Set the view mode
111
107
  */
@@ -162,7 +158,8 @@ export class ConstantsTreeProvider extends BaseTreeProvider<ConstantTreeItem> {
162
158
  data: { byCategory: Record<string, number> };
163
159
  }>('drift/constants', { action: 'status' });
164
160
 
165
- const categories = Object.entries(response.data.byCategory || {})
161
+ const byCategory = response.data.byCategory ?? {};
162
+ const categories = Object.entries(byCategory)
166
163
  .filter(([, count]) => count > 0)
167
164
  .sort(([, a], [, b]) => b - a);
168
165
 
@@ -180,7 +177,8 @@ export class ConstantsTreeProvider extends BaseTreeProvider<ConstantTreeItem> {
180
177
  data: { byLanguage: Record<string, number> };
181
178
  }>('drift/constants', { action: 'status' });
182
179
 
183
- const languages = Object.entries(response.data.byLanguage || {})
180
+ const byLanguage = response.data.byLanguage ?? {};
181
+ const languages = Object.entries(byLanguage)
184
182
  .filter(([, count]) => count > 0)
185
183
  .sort(([, a], [, b]) => b - a);
186
184
 
@@ -204,7 +202,7 @@ export class ConstantsTreeProvider extends BaseTreeProvider<ConstantTreeItem> {
204
202
  };
205
203
  }>('drift/constants', { action: 'status' });
206
204
 
207
- const issues = response.data.issues || {
205
+ const issues = response.data.issues ?? {
208
206
  potentialSecrets: 0,
209
207
  inconsistentValues: 0,
210
208
  deadConstants: 0,
@@ -246,11 +244,11 @@ export class ConstantsTreeProvider extends BaseTreeProvider<ConstantTreeItem> {
246
244
 
247
245
  const items: ConstantTreeItem[] = [];
248
246
 
249
- for (const constant of response.data.constants || []) {
247
+ for (const constant of response.data.constants ?? []) {
250
248
  items.push(this.createConstantItem(constant));
251
249
  }
252
250
 
253
- for (const enumDef of response.data.enums || []) {
251
+ for (const enumDef of response.data.enums ?? []) {
254
252
  items.push(this.createEnumItem(enumDef));
255
253
  }
256
254
 
@@ -268,11 +266,11 @@ export class ConstantsTreeProvider extends BaseTreeProvider<ConstantTreeItem> {
268
266
 
269
267
  const items: ConstantTreeItem[] = [];
270
268
 
271
- for (const constant of response.data.constants || []) {
269
+ for (const constant of response.data.constants ?? []) {
272
270
  items.push(this.createConstantItem(constant));
273
271
  }
274
272
 
275
- for (const enumDef of response.data.enums || []) {
273
+ for (const enumDef of response.data.enums ?? []) {
276
274
  items.push(this.createEnumItem(enumDef));
277
275
  }
278
276
 
@@ -289,7 +287,7 @@ export class ConstantsTreeProvider extends BaseTreeProvider<ConstantTreeItem> {
289
287
  data: { potentialSecrets: SecretIssue[] };
290
288
  }>('drift/constants', { action: 'secrets', limit: 50 });
291
289
 
292
- return (response.data.potentialSecrets || []).map((secret) =>
290
+ return (response.data.potentialSecrets ?? []).map((secret) =>
293
291
  this.createSecretItem(secret)
294
292
  );
295
293
  }
@@ -299,7 +297,7 @@ export class ConstantsTreeProvider extends BaseTreeProvider<ConstantTreeItem> {
299
297
  data: { inconsistencies: InconsistentIssue[] };
300
298
  }>('drift/constants', { action: 'inconsistent', limit: 50 });
301
299
 
302
- return (response.data.inconsistencies || []).map((inc) =>
300
+ return (response.data.inconsistencies ?? []).map((inc) =>
303
301
  this.createInconsistentItem(inc)
304
302
  );
305
303
  }
@@ -309,7 +307,7 @@ export class ConstantsTreeProvider extends BaseTreeProvider<ConstantTreeItem> {
309
307
  data: { deadConstants: Array<{ id: string; name: string; file: string; line: number }> };
310
308
  }>('drift/constants', { action: 'dead', limit: 50 });
311
309
 
312
- return (response.data.deadConstants || []).map((dead) =>
310
+ return (response.data.deadConstants ?? []).map((dead) =>
313
311
  this.createDeadItem(dead)
314
312
  );
315
313
  }
@@ -324,7 +322,7 @@ export class ConstantsTreeProvider extends BaseTreeProvider<ConstantTreeItem> {
324
322
  return {
325
323
  type: 'category',
326
324
  label: category.name,
327
- description: `${category.count} constants`,
325
+ description: `${String(category.count)} constants`,
328
326
  iconPath: this.getCategoryIcon(category.name),
329
327
  collapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
330
328
  contextValue: 'constant-category',
@@ -336,7 +334,7 @@ export class ConstantsTreeProvider extends BaseTreeProvider<ConstantTreeItem> {
336
334
  return {
337
335
  type: 'language',
338
336
  label: language.name,
339
- description: `${language.count} constants`,
337
+ description: `${String(language.count)} constants`,
340
338
  iconPath: this.getLanguageIcon(language.name),
341
339
  collapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
342
340
  contextValue: 'constant-language',
@@ -359,7 +357,7 @@ export class ConstantsTreeProvider extends BaseTreeProvider<ConstantTreeItem> {
359
357
  return {
360
358
  type: 'issue-group',
361
359
  label: name,
362
- description: `${count} issues`,
360
+ description: `${String(count)} issues`,
363
361
  iconPath: new vscode.ThemeIcon(icon, new vscode.ThemeColor(color)),
364
362
  collapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
365
363
  contextValue: 'constant-issue-group',
@@ -433,7 +431,7 @@ export class ConstantsTreeProvider extends BaseTreeProvider<ConstantTreeItem> {
433
431
  return {
434
432
  type: 'inconsistent',
435
433
  label: inc.name,
436
- description: `${inc.instanceCount} different values`,
434
+ description: `${String(inc.instanceCount)} different values`,
437
435
  iconPath: new vscode.ThemeIcon('warning', new vscode.ThemeColor('charts.yellow')),
438
436
  collapsibleState: vscode.TreeItemCollapsibleState.None,
439
437
  contextValue: 'constant-inconsistent',
@@ -501,7 +499,7 @@ export class ConstantsTreeProvider extends BaseTreeProvider<ConstantTreeItem> {
501
499
 
502
500
  md.appendMarkdown(`### ${constant.name}\n\n`);
503
501
  md.appendMarkdown(`**Qualified Name:** \`${constant.qualifiedName}\`\n\n`);
504
- md.appendMarkdown(`**File:** ${constant.file}:${constant.line}\n\n`);
502
+ md.appendMarkdown(`**File:** ${constant.file}:${String(constant.line)}\n\n`);
505
503
  md.appendMarkdown(`**Language:** ${constant.language}\n\n`);
506
504
  md.appendMarkdown(`**Kind:** ${constant.kind}\n\n`);
507
505
  md.appendMarkdown(`**Category:** ${constant.category}\n\n`);
@@ -29,10 +29,6 @@ export interface FileTreeItem extends BaseTreeItem {
29
29
  * Files tree provider
30
30
  */
31
31
  export class FilesTreeProvider extends BaseTreeProvider<FileTreeItem> {
32
- constructor(client: LanguageClient | null) {
33
- super(client);
34
- }
35
-
36
32
  async getChildren(element?: FileTreeItem): Promise<FileTreeItem[]> {
37
33
  if (!this.client) {
38
34
  return [];
@@ -1,4 +0,0 @@
1
-
2
- > driftdetect-vscode@0.9.32 build /Users/geoffreyfernald/drift/drift/packages/vscode
3
- > tsc -p tsconfig.json
4
-
@@ -1,4 +0,0 @@
1
-
2
- > driftdetect-vscode@0.9.30 lint /Users/geoffreyfernald/drift/drift/packages/vscode
3
- > eslint src --ext .ts,.tsx
4
-
@@ -1,34 +0,0 @@
1
-
2
- > driftdetect-vscode@0.9.30 test /Users/geoffreyfernald/drift/drift/packages/vscode
3
- > vitest run "--run"
4
-
5
-
6
- RUN v1.6.1 /Users/geoffreyfernald/drift/drift/packages/vscode
7
-
8
- [@drift/core] Config
9
- include: **/*.{test,spec}.{ts,tsx}, src/**/*.{test,spec}.ts, tests/**/*.{test,spec}.ts
10
- exclude: **/node_modules/**, **/dist/**, **/.turbo/**
11
- [@drift/detectors] Config
12
- include: **/*.{test,spec}.{ts,tsx}, src/**/*.{test,spec}.ts, tests/**/*.{test,spec}.ts
13
- exclude: **/node_modules/**, **/dist/**, **/.turbo/**
14
- [@drift/lsp] Config
15
- include: **/*.{test,spec}.{ts,tsx}, src/**/*.{test,spec}.ts, tests/**/*.{test,spec}.ts
16
- exclude: **/node_modules/**, **/dist/**, **/.turbo/**
17
- No test files found, exiting with code 0
18
-
19
- [@drift/cli] Config
20
- include: **/*.{test,spec}.{ts,tsx}, src/**/*.{test,spec}.ts, tests/**/*.{test,spec}.ts
21
- exclude: **/node_modules/**, **/dist/**, **/.turbo/**
22
- [@drift/ai] Config
23
- include: **/*.{test,spec}.{ts,tsx}, src/**/*.{test,spec}.ts, tests/**/*.{test,spec}.ts
24
- exclude: **/node_modules/**, **/dist/**, **/.turbo/**
25
- [@drift/vscode] Config
26
- include: **/*.{test,spec}.{ts,tsx}, src/**/*.{test,spec}.ts, tests/**/*.{test,spec}.ts
27
- exclude: **/node_modules/**, **/dist/**, **/.turbo/**
28
- [@drift/dashboard] Config
29
- include: **/*.{test,spec}.{ts,tsx}, src/**/*.{test,spec}.ts, src/**/*.{test,spec}.tsx, tests/**/*.{test,spec}.ts
30
- exclude: **/node_modules/**, **/dist/**, **/.turbo/**
31
- [@drift/mcp] Config
32
- include: **/*.{test,spec}.{ts,tsx}, src/**/*.{test,spec}.ts, tests/**/*.{test,spec}.ts
33
- exclude: **/node_modules/**, **/dist/**, **/.turbo/**
34
- watch exclude: **/node_modules/**, **/dist/**
package/LICENSE DELETED
@@ -1,121 +0,0 @@
1
- Apache License
2
- Version 2.0, January 2004
3
- http://www.apache.org/licenses/
4
-
5
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
-
7
- 1. Definitions.
8
-
9
- "License" shall mean the terms and conditions for use, reproduction,
10
- and distribution as defined by Sections 1 through 9 of this document.
11
-
12
- "Licensor" shall mean the copyright owner or entity authorized by
13
- the copyright owner that is granting the License.
14
-
15
- "Legal Entity" shall mean the union of the acting entity and all
16
- other entities that control, are controlled by, or are under common
17
- control with that entity. For the purposes of this definition,
18
- "control" means (i) the power, direct or indirect, to cause the
19
- direction or management of such entity, whether by contract or
20
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
- outstanding shares, or (iii) beneficial ownership of such entity.
22
-
23
- "You" (or "Your") shall mean an individual or Legal Entity
24
- exercising permissions granted by this License.
25
-
26
- "Source" form shall mean the preferred form for making modifications,
27
- including but not limited to software source code, documentation
28
- source, and configuration files.
29
-
30
- "Object" form shall mean any form resulting from mechanical
31
- transformation or translation of a Source form, including but
32
- not limited to compiled object code, generated documentation,
33
- and conversions to other media types.
34
-
35
- "Work" shall mean the work of authorship, whether in Source or
36
- Object form, made available under the License, as indicated by a
37
- copyright notice that is included in or attached to the work.
38
-
39
- "Derivative Works" shall mean any work, whether in Source or Object
40
- form, that is based on (or derived from) the Work and for which the
41
- editorial revisions, annotations, elaborations, or other modifications
42
- represent, as a whole, an original work of authorship.
43
-
44
- "Contribution" shall mean any work of authorship, including
45
- the original version of the Work and any modifications or additions
46
- to that Work or Derivative Works thereof, that is intentionally
47
- submitted to the Licensor for inclusion in the Work by the copyright owner.
48
-
49
- "Contributor" shall mean Licensor and any individual or Legal Entity
50
- on behalf of whom a Contribution has been received by Licensor and
51
- subsequently incorporated within the Work.
52
-
53
- 2. Grant of Copyright License. Subject to the terms and conditions of
54
- this License, each Contributor hereby grants to You a perpetual,
55
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
56
- copyright license to reproduce, prepare Derivative Works of,
57
- publicly display, publicly perform, sublicense, and distribute the
58
- Work and such Derivative Works in Source or Object form.
59
-
60
- 3. Grant of Patent License. Subject to the terms and conditions of
61
- this License, each Contributor hereby grants to You a perpetual,
62
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
63
- patent license to make, have made, use, offer to sell, sell, import,
64
- and otherwise transfer the Work.
65
-
66
- 4. Redistribution. You may reproduce and distribute copies of the
67
- Work or Derivative Works thereof in any medium, with or without
68
- modifications, and in Source or Object form, provided that You
69
- meet the following conditions:
70
-
71
- (a) You must give any other recipients of the Work or
72
- Derivative Works a copy of this License; and
73
-
74
- (b) You must cause any modified files to carry prominent notices
75
- stating that You changed the files; and
76
-
77
- (c) You must retain, in the Source form of any Derivative Works
78
- that You distribute, all copyright, patent, trademark, and
79
- attribution notices from the Source form of the Work; and
80
-
81
- (d) If the Work includes a "NOTICE" text file as part of its
82
- distribution, then any Derivative Works that You distribute must
83
- include a readable copy of the attribution notices contained
84
- within such NOTICE file.
85
-
86
- 5. Submission of Contributions. Unless You explicitly state otherwise,
87
- any Contribution intentionally submitted for inclusion in the Work
88
- by You to the Licensor shall be under the terms and conditions of
89
- this License, without any additional terms or conditions.
90
-
91
- 6. Trademarks. This License does not grant permission to use the trade
92
- names, trademarks, service marks, or product names of the Licensor.
93
-
94
- 7. Disclaimer of Warranty. Unless required by applicable law or
95
- agreed to in writing, Licensor provides the Work on an "AS IS" BASIS,
96
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND.
97
-
98
- 8. Limitation of Liability. In no event and under no legal theory,
99
- shall any Contributor be liable to You for damages, including any
100
- direct, indirect, special, incidental, or consequential damages.
101
-
102
- 9. Accepting Warranty or Additional Liability. While redistributing
103
- the Work or Derivative Works thereof, You may choose to offer,
104
- and charge a fee for, acceptance of support, warranty, indemnity,
105
- or other liability obligations.
106
-
107
- END OF TERMS AND CONDITIONS
108
-
109
- Copyright 2025 Geoffrey Fernald
110
-
111
- Licensed under the Apache License, Version 2.0 (the "License");
112
- you may not use this file except in compliance with the License.
113
- You may obtain a copy of the License at
114
-
115
- http://www.apache.org/licenses/LICENSE-2.0
116
-
117
- Unless required by applicable law or agreed to in writing, software
118
- distributed under the License is distributed on an "AS IS" BASIS,
119
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
120
- See the License for the specific language governing permissions and
121
- limitations under the License.